rave-engine 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +33 -0
- package/README.md +354 -0
- package/bin/rave.js +204 -0
- package/package.json +68 -0
- package/src/birth/parseBirth.js +76 -0
- package/src/calc/astronomia.js +163 -0
- package/src/calc/ephemeris.js +61 -0
- package/src/calc/mandala.js +66 -0
- package/src/calc/profile.js +288 -0
- package/src/calc/swisseph.js +87 -0
- package/src/chart.js +84 -0
- package/src/hd/bodygraph.js +270 -0
- package/src/hd/houses.js +229 -0
- package/src/index.js +89 -0
- package/src/timezone/location.js +67 -0
- package/src/timezone/search.js +183 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Adam Blvck / Blvck Studios
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
rave-engine
|
|
2
|
+
Copyright (c) 2026 Adam Blvck / Blvck Studios
|
|
3
|
+
Licensed under the MIT License (see LICENSE).
|
|
4
|
+
|
|
5
|
+
This product includes and/or depends on the following third-party software:
|
|
6
|
+
|
|
7
|
+
- astronomia (https://github.com/commenthol/astronomia) — MIT License.
|
|
8
|
+
Used as the default, pure-JavaScript ephemeris backend (VSOP87 planetary
|
|
9
|
+
theory, lunar theory, sidereal time, nutation). Bundles its own data; no
|
|
10
|
+
external ephemeris files are required.
|
|
11
|
+
|
|
12
|
+
- luxon (https://github.com/moment/luxon) — MIT License.
|
|
13
|
+
Date/time and IANA timezone handling.
|
|
14
|
+
|
|
15
|
+
- @vvo/tzdb (https://github.com/vvo/tzdb) — MIT License.
|
|
16
|
+
IANA timezone metadata and current offsets.
|
|
17
|
+
|
|
18
|
+
- city-timezones (https://github.com/kevinroberts/city-timezones) — MIT License.
|
|
19
|
+
City → timezone and representative coordinate lookups.
|
|
20
|
+
|
|
21
|
+
Optional, NOT bundled or required:
|
|
22
|
+
|
|
23
|
+
- swisseph (https://github.com/mivion/swisseph) — AGPL / commercial dual
|
|
24
|
+
license. rave-engine can use it as an opt-in high-precision backend
|
|
25
|
+
(EPHE_BACKEND=swisseph) only if a consumer installs it themselves. It is not
|
|
26
|
+
a dependency of this package and none of its code or Astrodienst data files
|
|
27
|
+
are distributed with rave-engine.
|
|
28
|
+
|
|
29
|
+
Reference data:
|
|
30
|
+
|
|
31
|
+
- The Human Design bodygraph reference data (gate→center map and the 36
|
|
32
|
+
channels) and the Gene Keys / I-Ching mandala mapping are based on the
|
|
33
|
+
standard, widely-published Human Design and Gene Keys systems.
|
package/README.md
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# rave-engine
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/rave-engine)
|
|
4
|
+
[](#tests)
|
|
5
|
+
[](#tests)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](package.json)
|
|
8
|
+
[](#accuracy--precision)
|
|
9
|
+
|
|
10
|
+
**A pure-JavaScript Human Design & Gene Keys engine — with extended astrology - from the maintainer of official Gene Keys Profiler and Event Horizon Election Engine, and Gene Key's Integral Human Design.**
|
|
11
|
+
|
|
12
|
+
From a birth date, time and timezone (and an optional location), `rave-engine`
|
|
13
|
+
computes:
|
|
14
|
+
|
|
15
|
+
- 🧬 **Gene Keys** — the gene key (hexagram) + line for every sphere of the
|
|
16
|
+
Hologenetic Profile (`lifeswork`, `purpose`, `pearl`, `iq`, `eq`, …).
|
|
17
|
+
- ⚡ **Human Design** — the full bodygraph: every planetary gate activation
|
|
18
|
+
(13 bodies × Personality + Design), **activated gates**, **defined channels**,
|
|
19
|
+
**defined centers**, **open centers**, and the derived **Type**, **Authority**
|
|
20
|
+
and **Profile**.
|
|
21
|
+
- 🪐 **Astrology** — **Ascendant**, **Descendant**, **Midheaven (MC)**,
|
|
22
|
+
**IC**, and house cusps (**Placidus**, **Whole Sign** or **Equal**).
|
|
23
|
+
|
|
24
|
+
It is **pure JavaScript** — no native build, no `node-gyp`, and **no ephemeris
|
|
25
|
+
data files**. Planetary positions come from the MIT-licensed
|
|
26
|
+
[`astronomia`](https://github.com/commenthol/astronomia) package (VSOP87 + lunar
|
|
27
|
+
theory), validated to the exact gate/line against Swiss Ephemeris.
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="assets/rave-mandala.png" alt="The 64-gate Human Design / Gene Keys mandala wheel around the bodygraph" width="440">
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install rave-engine
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Quickstart
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
const { computeChart } = require('rave-engine');
|
|
43
|
+
|
|
44
|
+
const chart = computeChart({
|
|
45
|
+
birthdate: '1972-08-02', // YYYY-MM-DD (or YYYY-M-D)
|
|
46
|
+
birthtime: '14:30', // HH:mm (or H:mm, or HH:mm:ss)
|
|
47
|
+
timezone: 'Asia/Bangkok', // any IANA timezone
|
|
48
|
+
// location: { lat: 13.75, lng: 100.5 }, // optional — see "Location" below
|
|
49
|
+
// houseSystem: 'placidus', // 'placidus' | 'whole' | 'equal'
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
console.log(chart.humanDesign.type); // 'Manifesting Generator'
|
|
53
|
+
console.log(chart.humanDesign.authority); // 'Sacral'
|
|
54
|
+
console.log(chart.humanDesign.profile); // '3/5'
|
|
55
|
+
console.log(chart.geneKeys.spheres.lifeswork); // { gk: 33, line: 3 }
|
|
56
|
+
console.log(chart.astrology.angles.ascendant.sign); // 'Sagittarius'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`computeChart` returns three coherent sections:
|
|
60
|
+
|
|
61
|
+
```jsonc
|
|
62
|
+
{
|
|
63
|
+
"input": {
|
|
64
|
+
"birthdate": "1972-08-02", "birthtime": "14:30", "timezone": "Asia/Bangkok",
|
|
65
|
+
"birth_utc": "1972-08-02T07:30:00.000Z",
|
|
66
|
+
"location": { "lat": 13.75, "lng": 100.51, "city": "Bangkok", "source": "timezone-city" }
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
"geneKeys": {
|
|
70
|
+
"spheres": {
|
|
71
|
+
"lifeswork": { "gk": 33, "line": 3 },
|
|
72
|
+
"evolution": { "gk": 19, "line": 3 },
|
|
73
|
+
"radiance": { "gk": 24, "line": 5 },
|
|
74
|
+
"purpose": { "gk": 44, "line": 5 },
|
|
75
|
+
"iq": { "gk": 12, "line": 6 }, "eq": { "gk": 4, "line": 4 },
|
|
76
|
+
"pearl": { "gk": 10, "line": 2 }, "relating": { "gk": 4, "line": 1 },
|
|
77
|
+
"attraction": { "gk": 11, "line": 3 }, "sq": { "gk": 12, "line": 3 },
|
|
78
|
+
"core": { "gk": 12, "line": 1 }, "culture": { "gk": 58, "line": 5 },
|
|
79
|
+
"stability": { "gk": 16, "line": 1 }, "creativity": { "gk": 57, "line": 1 }
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
"humanDesign": {
|
|
84
|
+
"type": "Manifesting Generator",
|
|
85
|
+
"authority": "Sacral",
|
|
86
|
+
"profile": "3/5",
|
|
87
|
+
"definitionCount": 6,
|
|
88
|
+
"activatedGates": [4, 10, 11, 12, 16, 19, 24, 33, 34, 44, 45, 48, 51, 56, 57, 58, 60, 61, 62],
|
|
89
|
+
"definedChannels": [{ "key": "34-57", "gates": [34, 57], "centers": ["sacral", "spleen"], "name": "Power" }, "…"],
|
|
90
|
+
"definedCenters": ["head", "ajna", "throat", "g", "sacral", "spleen"],
|
|
91
|
+
"openCenters": ["heart", "solarplexus", "root"],
|
|
92
|
+
"centers": { "head": true, "ajna": true, "…": "…" },
|
|
93
|
+
"p_": { "sun": { "gate": 33, "line": 3, "color": 4, "retrograde": false, "longitude": 130.09, "…": "…" }, "…": "…" },
|
|
94
|
+
"d_": { "…": "…" },
|
|
95
|
+
"activations": { "personality": [ "…13 bodies…" ], "design": [ "…13 bodies…" ] }
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
"astrology": {
|
|
99
|
+
"location": { "lat": 13.75, "lng": 100.51, "city": "Bangkok" },
|
|
100
|
+
"angles": {
|
|
101
|
+
"ascendant": { "longitude": 249.97, "sign": "Sagittarius", "degInSign": 9.97, "gateLine": { "gate": 9, "line": 5 } },
|
|
102
|
+
"descendant": { "sign": "Gemini", "…": "…" },
|
|
103
|
+
"mc": { "sign": "Virgo", "…": "…" },
|
|
104
|
+
"ic": { "sign": "Pisces", "…": "…" }
|
|
105
|
+
},
|
|
106
|
+
"houses": { "system": "placidus", "cusps": [ { "house": 1, "longitude": 249.97, "sign": "Sagittarius" }, "…" ] }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
If no location can be resolved, `astrology` is `null` (everything else still
|
|
112
|
+
computes — astrology is the only part that needs a place of birth).
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 🌐 Free API & live site
|
|
117
|
+
|
|
118
|
+
**[rave-engine.netlify.app](https://rave-engine.netlify.app)** — a free, local-only
|
|
119
|
+
API and an in-browser playground. Every endpoint is a plain `GET` with open CORS,
|
|
120
|
+
so you can call it from a browser, a notebook, or hand it straight to an AI.
|
|
121
|
+
|
|
122
|
+
<p align="center">
|
|
123
|
+
<img src="assets/site-demo.png" alt="The rave-engine landing page with the live in-browser API demo computing a chart" width="760">
|
|
124
|
+
</p>
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
curl "https://rave-engine.netlify.app/api/chart?date=1972-08-02&time=14:30&tz=Asia/Bangkok"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
| Endpoint | Returns |
|
|
131
|
+
| --- | --- |
|
|
132
|
+
| `/api/chart` | Full chart — Gene Keys + Human Design + Astrology |
|
|
133
|
+
| `/api/genekeys` | Gene Keys spheres |
|
|
134
|
+
| `/api/humandesign` | Human Design bodygraph |
|
|
135
|
+
| `/api/astrology` | Ascendant / MC / houses |
|
|
136
|
+
| `/api/prompt` | A ready-to-paste **AI interpretation prompt** |
|
|
137
|
+
| `/api/timezones?q=bali` | IANA timezone search |
|
|
138
|
+
|
|
139
|
+
Params: `date=YYYY-MM-DD` · `time=HH:mm` · `tz=IANA` · `[lat lng house=placidus|whole|equal]`
|
|
140
|
+
|
|
141
|
+
Dark and light, fully responsive:
|
|
142
|
+
|
|
143
|
+
| Dark | Light |
|
|
144
|
+
| --- | --- |
|
|
145
|
+
| <img src="assets/site-hero.png" alt="rave-engine landing page, dark mode" width="380"> | <img src="assets/site-hero-light.png" alt="rave-engine landing page, light mode" width="380"> |
|
|
146
|
+
|
|
147
|
+
The site and API live in [`site/`](site) and [`netlify/functions/`](netlify/functions);
|
|
148
|
+
the deploy config is [`netlify.toml`](netlify.toml). Nothing about a birth ever
|
|
149
|
+
leaves the function — the ephemeris is computed in-process.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## The three layers
|
|
154
|
+
|
|
155
|
+
### 🧬 Gene Keys (the spheres)
|
|
156
|
+
|
|
157
|
+
<p align="center">
|
|
158
|
+
<img src="assets/hologenetic-profile.png" alt="Gene Keys Hologenetic Profile — the spheres and their planetary activations" width="380">
|
|
159
|
+
</p>
|
|
160
|
+
|
|
161
|
+
Each sphere is keyed by its gene key (`gk`, the I-Ching hexagram 1–64) and line
|
|
162
|
+
(1–6), mapped from a planet at the Personality (birth) or Design (~88° of solar
|
|
163
|
+
arc before birth) moment:
|
|
164
|
+
|
|
165
|
+
| Sphere | Source | Sphere | Source |
|
|
166
|
+
| --- | --- | --- | --- |
|
|
167
|
+
| `lifeswork` | Personality Sun | `attraction` | Design Moon |
|
|
168
|
+
| `evolution` | Personality Earth | `sq` | Design Venus |
|
|
169
|
+
| `radiance` | Design Sun | `core` | Design Mars |
|
|
170
|
+
| `purpose` | Design Earth | `culture` | Design Jupiter |
|
|
171
|
+
| `iq` | Personality Venus | `stability` | Design Saturn |
|
|
172
|
+
| `eq` | Personality Mars | `creativity` | Design Uranus |
|
|
173
|
+
| `pearl` | Personality Jupiter | `relating` | Personality Mercury |
|
|
174
|
+
|
|
175
|
+
### ⚡ Human Design (the bodygraph)
|
|
176
|
+
|
|
177
|
+
The bodygraph is derived from **26 activations** — 13 bodies (Sun, Earth, Moon,
|
|
178
|
+
North/South Node, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto)
|
|
179
|
+
at both the Personality and Design moments:
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
const { computeChart } = require('rave-engine');
|
|
183
|
+
const hd = computeChart({ birthdate: '1972-08-02', birthtime: '14:30', timezone: 'Asia/Bangkok' }).humanDesign;
|
|
184
|
+
|
|
185
|
+
hd.activatedGates; // [4, 10, 11, … ] — every gate lit by a planet
|
|
186
|
+
hd.definedChannels; // channels where BOTH gates are activated
|
|
187
|
+
hd.definedCenters; // centers touched by a defined channel
|
|
188
|
+
hd.openCenters; // the rest
|
|
189
|
+
hd.type; // Generator | Manifesting Generator | Projector | Manifestor | Reflector
|
|
190
|
+
hd.authority; // Emotional | Sacral | Splenic | Ego | Self-Projected | Mental | Lunar
|
|
191
|
+
hd.profile; // e.g. '3/5' (Personality Sun line / Design Sun line)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Reference data (gate→center map and the 36 channels) is the standard Human
|
|
195
|
+
Design bodygraph and is exported for your own use:
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
const { GATE_CENTER, CHANNELS, CENTERS, computeBodygraph } = require('rave-engine');
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 🪐 Astrology (angles & houses)
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
const { computeAngles, computeHouses } = require('rave-engine');
|
|
205
|
+
|
|
206
|
+
const angles = computeAngles({ jdUT: 2441531.8125, lat: 13.75, lng: 100.5 });
|
|
207
|
+
// { ascendant, descendant, mc, ic } — each with longitude, sign, degInSign, gateLine
|
|
208
|
+
|
|
209
|
+
const houses = computeHouses({ jdUT: 2441531.8125, lat: 13.75, lng: 100.5, system: 'placidus' });
|
|
210
|
+
// { system, cusps: [{ house, longitude, sign, degInSign }, …], angles }
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Angles and houses need only sidereal time + obliquity (no ephemeris). Placidus
|
|
214
|
+
falls back to Whole Sign above the polar circle, where it is mathematically
|
|
215
|
+
undefined.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Location
|
|
220
|
+
|
|
221
|
+
The astrology section needs a **place of birth**. You have two options:
|
|
222
|
+
|
|
223
|
+
1. **Explicit coordinates** (most accurate):
|
|
224
|
+
```js
|
|
225
|
+
computeChart({ /* … */ location: { lat: 13.7563, lng: 100.5018 } });
|
|
226
|
+
```
|
|
227
|
+
2. **Just the timezone** — `rave-engine` derives a representative location from
|
|
228
|
+
the most-populous city in that timezone, which is plenty for an Ascendant:
|
|
229
|
+
```js
|
|
230
|
+
computeChart({ birthdate, birthtime, timezone: 'Asia/Bangkok' });
|
|
231
|
+
// → location { city: 'Bangkok', lat: 13.75, lng: 100.51, source: 'timezone-city' }
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Coordinates use **north-positive latitude** and **east-positive longitude**.
|
|
235
|
+
|
|
236
|
+
### Historical timezones
|
|
237
|
+
|
|
238
|
+
Birth charts are historical, so the engine honours the **full IANA history** of
|
|
239
|
+
each zone — not just modern rules. Offsets resolve through
|
|
240
|
+
[Luxon](https://moment.github.io/luxon/) against the runtime's IANA/ICU tz
|
|
241
|
+
database, which correctly handles 20th-century edge cases such as US year-round
|
|
242
|
+
DST in 1974, British Double Summer Time (1944/1947 = UTC+2), Poland skipping DST
|
|
243
|
+
in 1970, Nepal's 1986 switch to UTC+5:45, and pre-standardisation Local Mean
|
|
244
|
+
Time. These are regression-locked in
|
|
245
|
+
[`test/timezone-history.test.js`](test/timezone-history.test.js).
|
|
246
|
+
|
|
247
|
+
> Accuracy of historical offsets depends on the tz database in your JS runtime.
|
|
248
|
+
> Use a current Node.js (full ICU is the default since Node 13) for complete
|
|
249
|
+
> 20th-century coverage. Nonexistent local times (spring-forward gaps) shift
|
|
250
|
+
> forward into DST; ambiguous times (fall-back overlaps) resolve to the earlier
|
|
251
|
+
> offset.
|
|
252
|
+
|
|
253
|
+
### Timezone autocomplete
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
const { searchTimezones, locationForTimezone } = require('rave-engine');
|
|
257
|
+
|
|
258
|
+
searchTimezones('bali'); // → [{ ianaName: 'Asia/Makassar', mainCity: 'Makassar', … }]
|
|
259
|
+
searchTimezones('tokyo'); // → [{ ianaName: 'Asia/Tokyo', currentOffsetMinutes: 540, … }]
|
|
260
|
+
locationForTimezone('Europe/London'); // → { lat: 51.5, lng: -0.12, city: 'London', … }
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## CLI
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# Full chart (readable summary)
|
|
269
|
+
npx rave --chart --date 1972-08-02 --time 14:30 --tz Asia/Bangkok
|
|
270
|
+
|
|
271
|
+
# With explicit coordinates and a house system, as JSON
|
|
272
|
+
npx rave --chart --date 1972-08-02 --time 14:30 --tz Asia/Bangkok \
|
|
273
|
+
--lat 13.75 --lng 100.5 --house whole --json
|
|
274
|
+
|
|
275
|
+
# Classic profile (p_/d_ + spheres)
|
|
276
|
+
npx rave --date 1972-08-02 --time 14:30 --tz Asia/Bangkok
|
|
277
|
+
|
|
278
|
+
# Timezone search
|
|
279
|
+
npx rave --tz-search bali
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Accuracy & precision
|
|
285
|
+
|
|
286
|
+
Planetary positions come from `astronomia` (VSOP87 + lunar theory) and match
|
|
287
|
+
Swiss Ephemeris to well within a Gene Keys **line** (0.9375°): typically `<1″`
|
|
288
|
+
for the Sun and planets and `~10″` for the Moon. The gate/line/retrograde output
|
|
289
|
+
is regression-locked against Swiss Ephemeris golden vectors (see
|
|
290
|
+
[`test/profile.test.js`](test/profile.test.js)) **and validated against five
|
|
291
|
+
real charts from a third-party calculator** — 125 of 130 body activations match
|
|
292
|
+
to the exact gate.line, with the remainder within a single line (design-Moon
|
|
293
|
+
timing, true-node algorithm and sub-line ephemeris differences between
|
|
294
|
+
calculators). See [`test/reference-charts.test.js`](test/reference-charts.test.js).
|
|
295
|
+
|
|
296
|
+
Lunar nodes use the **true node** (oscillating), matching mainstream Human
|
|
297
|
+
Design calculators.
|
|
298
|
+
|
|
299
|
+
### Optional high-precision backend
|
|
300
|
+
|
|
301
|
+
If you want Swiss Ephemeris precision (and accept its AGPL/commercial license),
|
|
302
|
+
install it yourself and opt in — it is **not** a dependency of this package:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
npm install swisseph # native build; provide ephemeris files via EPHE_PATH
|
|
306
|
+
EPHE_BACKEND=swisseph node your-app.js
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
`rave-engine` auto-detects it and falls back to the pure-JS backend if it isn't
|
|
310
|
+
available.
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## API
|
|
315
|
+
|
|
316
|
+
| Export | Returns |
|
|
317
|
+
| --- | --- |
|
|
318
|
+
| `computeChart(input)` | Full `{ input, geneKeys, humanDesign, astrology, _meta }` |
|
|
319
|
+
| `computeProfile(input)` | `{ input, engine: { p_, d_, spheres, _meta } }` (back-compat) |
|
|
320
|
+
| `computeBodygraph(activations)` | `{ type, authority, profile, activatedGates, definedChannels, definedCenters, openCenters, centers, … }` |
|
|
321
|
+
| `computeActivations({ birthUtc })` | The 26 raw activations (`{ personality, design }`) |
|
|
322
|
+
| `computeAngles({ jdUT, lat, lng })` | `{ ascendant, descendant, mc, ic }` |
|
|
323
|
+
| `computeHouses({ jdUT, lat, lng, system })` | `{ system, cusps, angles }` |
|
|
324
|
+
| `searchTimezones(query, { limit })` | Ranked IANA zones with offsets + city hints |
|
|
325
|
+
| `locationForTimezone(iana)` | Representative `{ lat, lng, city, country }` |
|
|
326
|
+
| `parseBirthToUtc({ birthdate, birthtime, timezone })` | UTC `Date` |
|
|
327
|
+
| `mapLongitudeDegrees(lon)` | `{ hexagram, line, color }` |
|
|
328
|
+
|
|
329
|
+
Also exported: `GATE_CENTER`, `CHANNELS`, `CENTERS`, `signOf`, `SIGNS`,
|
|
330
|
+
`resolveLocation`, `getBackend`.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Tests
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
npm test # run the suite
|
|
338
|
+
npm run coverage # run with a coverage report
|
|
339
|
+
npm run coverage:badge # refresh the coverage badge above from a fresh run
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
200+ tests covering: the mandala mapping, regression-locked profiles, the
|
|
343
|
+
bodygraph reference data + derivation, the astronomia backend, the astrology
|
|
344
|
+
angles/houses (verified against the horizon/meridian geometry), the location
|
|
345
|
+
lookup, the end-to-end chart, **five real reference charts** from a third-party
|
|
346
|
+
Swiss-Ephemeris calculator, and **historical IANA timezone offsets** across the
|
|
347
|
+
20th century.
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## License
|
|
352
|
+
|
|
353
|
+
MIT © Adam Blvck / Blvck Studios. See [LICENSE](LICENSE) and [NOTICE](NOTICE)
|
|
354
|
+
for third-party attributions.
|
package/bin/rave.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { computeProfile, computeChart, searchTimezones } = require('../src');
|
|
4
|
+
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
// Tiny argv parser. Supports `--key value` and `--key=value`. No deps.
|
|
7
|
+
const out = {};
|
|
8
|
+
const args = argv.slice(2);
|
|
9
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
10
|
+
const a = args[i];
|
|
11
|
+
if (!a.startsWith('--')) continue;
|
|
12
|
+
const eq = a.indexOf('=');
|
|
13
|
+
let key;
|
|
14
|
+
let val;
|
|
15
|
+
if (eq >= 0) {
|
|
16
|
+
key = a.slice(2, eq);
|
|
17
|
+
val = a.slice(eq + 1);
|
|
18
|
+
} else {
|
|
19
|
+
key = a.slice(2);
|
|
20
|
+
const next = args[i + 1];
|
|
21
|
+
if (next !== undefined && !next.startsWith('--')) {
|
|
22
|
+
val = next;
|
|
23
|
+
i += 1;
|
|
24
|
+
} else {
|
|
25
|
+
val = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
out[key] = val;
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function printUsage() {
|
|
34
|
+
const lines = [
|
|
35
|
+
'rave-engine CLI',
|
|
36
|
+
'',
|
|
37
|
+
'Compute a profile (p_/d_ + spheres):',
|
|
38
|
+
' rave --date 1972-08-02 --time 14:30 --tz Asia/Bangkok',
|
|
39
|
+
'',
|
|
40
|
+
'Compute the full chart (Gene Keys + Human Design + Astrology):',
|
|
41
|
+
' rave --chart --date 1972-08-02 --time 14:30 --tz Asia/Bangkok',
|
|
42
|
+
' rave --chart --date 1972-08-02 --time 14:30 --tz Asia/Bangkok --lat 13.75 --lng 100.5',
|
|
43
|
+
'',
|
|
44
|
+
'Aliases: --date|--birthdate, --time|--birthtime, --tz|--timezone',
|
|
45
|
+
'',
|
|
46
|
+
'Search timezones:',
|
|
47
|
+
' rave --tz-search bali',
|
|
48
|
+
' rave --tz-search "los ang" --limit 5',
|
|
49
|
+
'',
|
|
50
|
+
'Flags:',
|
|
51
|
+
' --chart Full Gene Keys + Human Design + Astrology output.',
|
|
52
|
+
' --lat --lng Birth coordinates (else derived from the timezone city).',
|
|
53
|
+
' --house House system for --chart: placidus|whole|equal (default placidus).',
|
|
54
|
+
' --json Print full JSON instead of the readable summary.',
|
|
55
|
+
' --pretty Indent output (default: 2 spaces).',
|
|
56
|
+
' --help Show this help.',
|
|
57
|
+
];
|
|
58
|
+
// eslint-disable-next-line no-console
|
|
59
|
+
console.log(lines.join('\n'));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function formatOffsetMinutes(min) {
|
|
63
|
+
const sign = min >= 0 ? '+' : '-';
|
|
64
|
+
const abs = Math.abs(min);
|
|
65
|
+
const hh = String(Math.floor(abs / 60)).padStart(2, '0');
|
|
66
|
+
const mm = String(abs % 60).padStart(2, '0');
|
|
67
|
+
return `${sign}${hh}:${mm}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function runTzSearch(query, limit) {
|
|
71
|
+
const results = searchTimezones(query, { limit });
|
|
72
|
+
if (results.length === 0) {
|
|
73
|
+
// eslint-disable-next-line no-console
|
|
74
|
+
console.log(`(no matches for "${query}")`);
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const widthIana = Math.max(...results.map((r) => r.ianaName.length));
|
|
79
|
+
for (const r of results) {
|
|
80
|
+
const offset = formatOffsetMinutes(r.currentOffsetMinutes);
|
|
81
|
+
const city = r.mainCity || '';
|
|
82
|
+
const country = r.countryName || '';
|
|
83
|
+
// eslint-disable-next-line no-console
|
|
84
|
+
console.log(
|
|
85
|
+
`${r.ianaName.padEnd(widthIana)} ${offset} ${city}${country ? `, ${country}` : ''}`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function printChartSummary(chart) {
|
|
92
|
+
const { geneKeys, humanDesign: hd, astrology } = chart;
|
|
93
|
+
const lines = [];
|
|
94
|
+
lines.push(`Birth (UTC): ${chart.input.birth_utc}`);
|
|
95
|
+
lines.push('');
|
|
96
|
+
lines.push('— Human Design —');
|
|
97
|
+
lines.push(` Type: ${hd.type}`);
|
|
98
|
+
lines.push(` Authority: ${hd.authority}`);
|
|
99
|
+
lines.push(` Profile: ${hd.profile}`);
|
|
100
|
+
lines.push(` Definition:${hd.definitionCount} channels`);
|
|
101
|
+
lines.push(` Defined centers: ${hd.definedCenters.join(', ') || '(none)'}`);
|
|
102
|
+
lines.push(` Open centers: ${hd.openCenters.join(', ') || '(none)'}`);
|
|
103
|
+
lines.push(` Channels: ${hd.definedChannels.map((c) => `${c.key}${c.name ? ` (${c.name})` : ''}`).join(', ') || '(none)'}`);
|
|
104
|
+
lines.push(` Activated gates: ${hd.activatedGates.join(', ')}`);
|
|
105
|
+
lines.push('');
|
|
106
|
+
lines.push('— Gene Keys (spheres) —');
|
|
107
|
+
for (const [sphere, v] of Object.entries(geneKeys.spheres)) {
|
|
108
|
+
lines.push(` ${sphere.padEnd(11)} ${v.gk}.${v.line}`);
|
|
109
|
+
}
|
|
110
|
+
if (astrology) {
|
|
111
|
+
lines.push('');
|
|
112
|
+
lines.push(`— Astrology (${astrology.location.city || 'lat/lng'}, ${astrology.houses.system} houses) —`);
|
|
113
|
+
const a = astrology.angles;
|
|
114
|
+
const fa = (x) => `${x.sign} ${x.degInSign.toFixed(2)}°`;
|
|
115
|
+
lines.push(` Ascendant: ${fa(a.ascendant)}`);
|
|
116
|
+
lines.push(` Descendant: ${fa(a.descendant)}`);
|
|
117
|
+
lines.push(` MC: ${fa(a.mc)}`);
|
|
118
|
+
lines.push(` IC: ${fa(a.ic)}`);
|
|
119
|
+
} else {
|
|
120
|
+
lines.push('');
|
|
121
|
+
lines.push('— Astrology — (no location resolved; pass --lat/--lng or a recognized --tz)');
|
|
122
|
+
}
|
|
123
|
+
return lines.join('\n');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function runChart(args) {
|
|
127
|
+
const birthdate = args.date || args.birthdate;
|
|
128
|
+
const birthtime = args.time || args.birthtime;
|
|
129
|
+
const timezone = args.tz || args.timezone;
|
|
130
|
+
if (!birthdate || !birthtime || !timezone) {
|
|
131
|
+
// eslint-disable-next-line no-console
|
|
132
|
+
console.error('error: --date, --time and --tz are all required\n');
|
|
133
|
+
printUsage();
|
|
134
|
+
return 2;
|
|
135
|
+
}
|
|
136
|
+
const lat = Number(args.lat);
|
|
137
|
+
const lng = Number(args.lng);
|
|
138
|
+
const location =
|
|
139
|
+
Number.isFinite(lat) && Number.isFinite(lng) ? { lat, lng } : undefined;
|
|
140
|
+
const chart = computeChart({
|
|
141
|
+
birthdate,
|
|
142
|
+
birthtime,
|
|
143
|
+
timezone,
|
|
144
|
+
location,
|
|
145
|
+
houseSystem: args.house || 'placidus',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
if (args.json) {
|
|
149
|
+
const indent = args.pretty === false ? 0 : 2;
|
|
150
|
+
// eslint-disable-next-line no-console
|
|
151
|
+
console.log(JSON.stringify(chart, null, indent));
|
|
152
|
+
} else {
|
|
153
|
+
// eslint-disable-next-line no-console
|
|
154
|
+
console.log(printChartSummary(chart));
|
|
155
|
+
}
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function runProfile(args) {
|
|
160
|
+
const birthdate = args.date || args.birthdate;
|
|
161
|
+
const birthtime = args.time || args.birthtime;
|
|
162
|
+
const timezone = args.tz || args.timezone;
|
|
163
|
+
|
|
164
|
+
if (!birthdate || !birthtime || !timezone) {
|
|
165
|
+
// eslint-disable-next-line no-console
|
|
166
|
+
console.error('error: --date, --time and --tz are all required\n');
|
|
167
|
+
printUsage();
|
|
168
|
+
return 2;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const out = computeProfile({ birthdate, birthtime, timezone });
|
|
172
|
+
const indent = args.pretty === false ? 0 : 2;
|
|
173
|
+
// eslint-disable-next-line no-console
|
|
174
|
+
console.log(JSON.stringify(out, null, indent));
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function main(argv) {
|
|
179
|
+
const args = parseArgs(argv);
|
|
180
|
+
|
|
181
|
+
if (args.help || args.h) {
|
|
182
|
+
printUsage();
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (args['tz-search'] !== undefined && args['tz-search'] !== true) {
|
|
187
|
+
const limit = Number.isFinite(Number(args.limit)) ? Number(args.limit) : 10;
|
|
188
|
+
return runTzSearch(String(args['tz-search']), limit);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (args.chart) {
|
|
192
|
+
return runChart(args);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return runProfile(args);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
process.exitCode = main(process.argv) || 0;
|
|
200
|
+
} catch (e) {
|
|
201
|
+
// eslint-disable-next-line no-console
|
|
202
|
+
console.error(`error: ${e?.message || e}`);
|
|
203
|
+
process.exitCode = 1;
|
|
204
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rave-engine",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Pure-JS Human Design & Gene Keys engine: gates, lines, centers, channels and a full bodygraph (Type/Authority/Profile), plus extended astrology (Ascendant/MC/houses) and IANA timezone tools. No native build, no ephemeris data files.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"rave": "bin/rave.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./src/index.js",
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"src",
|
|
16
|
+
"bin",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"NOTICE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "jest",
|
|
23
|
+
"coverage": "jest --coverage",
|
|
24
|
+
"coverage:badge": "jest --coverage && node scripts/make-coverage-badge.js",
|
|
25
|
+
"cli": "node bin/rave.js",
|
|
26
|
+
"prepublishOnly": "jest"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"human-design",
|
|
30
|
+
"gene-keys",
|
|
31
|
+
"bodygraph",
|
|
32
|
+
"astrology",
|
|
33
|
+
"ephemeris",
|
|
34
|
+
"natal-chart",
|
|
35
|
+
"ascendant",
|
|
36
|
+
"midheaven",
|
|
37
|
+
"houses",
|
|
38
|
+
"placidus",
|
|
39
|
+
"i-ching",
|
|
40
|
+
"hexagram",
|
|
41
|
+
"gates",
|
|
42
|
+
"channels",
|
|
43
|
+
"centers",
|
|
44
|
+
"timezone"
|
|
45
|
+
],
|
|
46
|
+
"author": "Adam Blvck <adam@blvckstudios.com>",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"homepage": "https://rave-engine.netlify.app",
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/adamblvck/rave-engine.git"
|
|
52
|
+
},
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/adamblvck/rave-engine/issues"
|
|
55
|
+
},
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=16"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@vvo/tzdb": "^6.157.0",
|
|
61
|
+
"astronomia": "^4.2.0",
|
|
62
|
+
"city-timezones": "^1.3.0",
|
|
63
|
+
"luxon": "^3.5.0"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"jest": "^30.3.0"
|
|
67
|
+
}
|
|
68
|
+
}
|