tonus 0.5.0 → 0.6.1
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/BIBLIOGRAPHY.md +6 -0
- package/CHANGELOG.md +66 -0
- package/README.md +75 -71
- package/dist/data/gabc-glyphs.js +1 -1
- package/dist/data/smufl-glyphs.js +4 -4
- package/dist/data/smufl-glyphs.json +3 -3
- package/dist/engines/harmonia/data/zodiac.d.ts +47 -0
- package/dist/engines/harmonia/data/zodiac.js +163 -0
- package/dist/engines/score/emitters/svg.js +8 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -2
- package/docs/api/heavens.md +50 -0
- package/docs/api/index.md +18 -16
- package/docs/api/score.md +33 -0
- package/package.json +4 -2
package/BIBLIOGRAPHY.md
CHANGED
|
@@ -126,6 +126,12 @@ doctrine tables, and the references behind them. Code cites by bracketed key
|
|
|
126
126
|
shades) and III with the Canobic Inscription (c. 150).** The tetrachord
|
|
127
127
|
genera for the tuning presets; the Greater Perfect System tone assignments
|
|
128
128
|
and aspect–consonance mapping for the doctrina.
|
|
129
|
+
- `ptolemy-tetrabiblos` — **Ptolemy. _Tetrabiblos_ I.17 (the domiciles) and
|
|
130
|
+
I.19 (the exaltations) (c. 150).** The rulerships and the triplicity and
|
|
131
|
+
quadruplicity classifications, transmitted whole through the medieval Latin
|
|
132
|
+
tradition and uncontested across sources; the ground of the zodiac doctrine
|
|
133
|
+
table. The exaltation degrees it gives (the Sun at 19° Arietis and the rest)
|
|
134
|
+
are not carried — the sign is the resolution anything here reads.
|
|
129
135
|
- `schulter-harmony` — **Schulter, Margo. Medieval Music & Arts Foundation
|
|
130
136
|
harmony FAQs:** "Pythagorean Tuning and Medieval Polyphony"
|
|
131
137
|
(<https://www.medieval.org/emfaq/harmony/pyth.html>) and "Hexachords,
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,72 @@ All notable changes to tonus. Newest first.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.6.0 — 2026-08-16
|
|
8
|
+
|
|
9
|
+
The zodiac learns what it means, and the hand stops sitting on its own floor.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`ZODIACA` — the doctrine of the twelve signs.** `caelum` answers WHERE a
|
|
14
|
+
body is; this answers what a medieval reader brought to that position: the
|
|
15
|
+
element and its Galenic humor, the quality, the ruling and exalted planets,
|
|
16
|
+
and the member of the zodiac man the sign governs. `ZODIACA[body.zodiac]` is
|
|
17
|
+
the join, so a sky and its meaning are one lookup apart.
|
|
18
|
+
|
|
19
|
+
Deliberately no dates. When the Sun enters a sign is the ephemeris's business
|
|
20
|
+
and moves with precession — a table carrying "March 21" would be wrong for
|
|
21
|
+
most of the period this library models, and wrong differently every century.
|
|
22
|
+
|
|
23
|
+
The exaltation degrees are omitted (the sign is the resolution anything here
|
|
24
|
+
reads) and so are the lunar nodes, which are not tonus bodies. Five signs
|
|
25
|
+
exalt nobody, and that silence is the tradition's.
|
|
26
|
+
|
|
27
|
+
### Changed — breaking
|
|
28
|
+
|
|
29
|
+
- **`SIGNS` and `SIGNA` are no longer exported.** `ZODIACA` carries each sign's
|
|
30
|
+
own `sign` and `signum` beside its doctrine, so it answers both what a sign
|
|
31
|
+
is called and what it means. The bare name arrays go back to being internal
|
|
32
|
+
to the engine that computes a longitude, which is the only place they were a
|
|
33
|
+
lookup rather than a listing.
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
// before
|
|
37
|
+
import tonus, { SIGNS, SIGNA } from "tonus";
|
|
38
|
+
SIGNS[body.zodiac]; // "Capricorn"
|
|
39
|
+
SIGNA[body.zodiac]; // "Capricornus"
|
|
40
|
+
|
|
41
|
+
// after
|
|
42
|
+
import tonus, { ZODIACA } from "tonus";
|
|
43
|
+
ZODIACA[body.zodiac].sign; // "Capricorn"
|
|
44
|
+
ZODIACA[body.zodiac].signum; // "Capricornus"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- **The Manus line reads the note that was clicked.** The subheader found its
|
|
50
|
+
row by pitch, and `find(r => r.spn === spn)` returns the FIRST note of the
|
|
51
|
+
chant at that pitch — so clicking the second E of a porrectus flexus
|
|
52
|
+
described an E in a torculus eleven notes earlier, with that note's neume,
|
|
53
|
+
joint and Guidonian name.
|
|
54
|
+
|
|
55
|
+
### Site
|
|
56
|
+
|
|
57
|
+
- **The chant is lifted onto the hand automatically, by whole octaves.** Almost
|
|
58
|
+
nothing fits the gamut as printed: measured over 400 chants, 32 sit inside
|
|
59
|
+
their mode's gamut and 346 sit below it, so a piece read straight lands on
|
|
60
|
+
the bottom joint and stays there. The lift is computed from the chant's own
|
|
61
|
+
lowest note, which takes notes landing on a joint from 68.8% to 99.9%. The
|
|
62
|
+
`octava` button was the manual version of this and is gone.
|
|
63
|
+
- **The three sung hours become one Officium segment**, with all eight hours in
|
|
64
|
+
its popover — Matins and Vespers on, the little hours and Compline there to
|
|
65
|
+
be asked for.
|
|
66
|
+
- **The address bar keeps `cantus` and nothing else.** Eleven parameters were
|
|
67
|
+
mirrored there, each written the moment it moved off its default, which made
|
|
68
|
+
the bar a running transcript of a session.
|
|
69
|
+
- All three analysis tracks open together; the Similes subheader reports the
|
|
70
|
+
company a melody keeps rather than describing the list; the temperament
|
|
71
|
+
slider steps a tenth of a cent, the precision its readout prints.
|
|
72
|
+
|
|
7
73
|
## 0.5.0 — 2026-08-12
|
|
8
74
|
|
|
9
75
|
Rendering, mostly — a day of looking at real chant on a real page and fixing
|
package/README.md
CHANGED
|
@@ -1,79 +1,19 @@
|
|
|
1
1
|
# tonus
|
|
2
2
|
|
|
3
3
|
**tonus** is a JavaScript library for medieval music theory and chant
|
|
4
|
-
analysis. It carries the Gregorian repertoire and the
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
analysis. It carries the Gregorian repertoire and the concepts it was built on.
|
|
5
|
+
|
|
6
|
+
It tunes to scales medieval singers would have used, tells you which chants
|
|
7
|
+
belong to which day and returns analysis and notation, and calculates the
|
|
8
|
+
_music of the spheres_ proposed by Pythagoras, Boethius, and more as real
|
|
9
|
+
intervals.
|
|
10
|
+
|
|
11
|
+
**[Interactive demo →](https://jeffreypierce.github.io/tonus/)**
|
|
8
12
|
|
|
9
13
|
Everything is computed locally and deterministically: the same question always
|
|
10
14
|
returns the same answer, from data that ships inside the package, with no network
|
|
11
15
|
calls and no runtime dependencies.
|
|
12
16
|
|
|
13
|
-
## What it covers
|
|
14
|
-
|
|
15
|
-
- **Pitch and tuning.** The medieval pitch world: Pythagorean and meantone
|
|
16
|
-
temperaments, just intonation and custom scales, the Guidonian gamut and hand,
|
|
17
|
-
hexachords and their mutations, and interval analysis by name.
|
|
18
|
-
- **The eight modes.** Each church mode with its final, dominant, ambitus, and
|
|
19
|
-
ethos, and the psalm tones that go with them.
|
|
20
|
-
- **The liturgical calendar.** The Tridentine calendar of any year, resolved
|
|
21
|
-
against Easter (by the Julian or the Gregorian computus), with each feast's
|
|
22
|
-
rank, grade, and season.
|
|
23
|
-
- **The chant repertoire.** About 2,200 chants across ten books (nine Solesmes
|
|
24
|
-
editions and the Nocturnale Romanum night office), in
|
|
25
|
-
[GABC](https://gregorio-project.github.io/) notation: Mass propers, the Kyriale,
|
|
26
|
-
the Office hours, the psalter, and the Matins nocturns, retrievable by feast,
|
|
27
|
-
season, mode, or office.
|
|
28
|
-
- **Rhythm and notation.** GABC parsed into phrases, syllables, and tuned notes,
|
|
29
|
-
shaped by the Solesmes arsis/thesis rhythm, with an analytic fingerprint of a
|
|
30
|
-
chant's melodic character, and drawn to a square-note or modern staff.
|
|
31
|
-
- **The harmony of the spheres.** An ephemeris of the classical planets, voiced
|
|
32
|
-
as tuned pitch after Boethius, Nicomachus, Pliny, and Ptolemy.
|
|
33
|
-
- **The census.** Every shipped chant measured against the corpus that holds
|
|
34
|
-
it: how typical it is, where it is unusual, and its nearest neighbours by
|
|
35
|
-
melodic shape.
|
|
36
|
-
|
|
37
|
-
## The ideas behind it
|
|
38
|
-
|
|
39
|
-
Boethius's _De institutione musica_ carried Greek theory into the Latin
|
|
40
|
-
Middle Ages, and it treats music as a branch of number, beside arithmetic,
|
|
41
|
-
geometry, and astronomy. Its music runs from the audible to the inaudible:
|
|
42
|
-
voices and instruments (_musica instrumentalis_), body and soul (_musica
|
|
43
|
-
humana_), the turning cosmos (_musica mundana_). Chant was composed and
|
|
44
|
-
copied inside that frame: pitch was ratio, the modes a received order, the
|
|
45
|
-
heavens harmonic proportion.
|
|
46
|
-
|
|
47
|
-
tonus takes those claims literally enough to compute them. It tunes pitch in
|
|
48
|
-
the Pythagorean ratios of the treatises. It reads the calendar as the
|
|
49
|
-
retrieval index it was for a millennium. It follows the Solesmes rhythm of
|
|
50
|
-
arsis and thesis. And it computes _musica mundana_ as sounding pitch. Where
|
|
51
|
-
the sources run out or contradict one another, tonus makes an editorial call
|
|
52
|
-
and records it in the code.
|
|
53
|
-
|
|
54
|
-
tonus is an instrument for study. It treats this repertoire as musical and
|
|
55
|
-
historical material to be measured, queried, and understood; what it models is
|
|
56
|
-
the sound and its structure.
|
|
57
|
-
|
|
58
|
-
## Sources
|
|
59
|
-
|
|
60
|
-
tonus is built on primary and scholarly sources, and it names them wherever it
|
|
61
|
-
makes a choice. The chant and calendar data are the Solesmes editions, by way of
|
|
62
|
-
[GregoBase](https://gregobase.selapa.net/),
|
|
63
|
-
[Divinum Officium](https://divinumofficium.com/), and the community _Nocturnale
|
|
64
|
-
Romanum_. The rhythm follows Mocquereau, Gajard, Suñol, and Daniel Saulnier; the
|
|
65
|
-
modes and cadences follow Rockstro's _Grove_ article, Niedermeyer & d'Ortigue,
|
|
66
|
-
and Apel; the tuning follows Boethius's _De institutione musica_ and Ptolemy's
|
|
67
|
-
_Harmonics_; the notation is engraved in Daniel Spreadbury's
|
|
68
|
-
[Bravura](https://github.com/steinbergmedia/bravura), the reference font for the
|
|
69
|
-
SMuFL standard; the planetary doctrines follow Godwin's sourcebooks of the
|
|
70
|
-
Pythagorean tradition.
|
|
71
|
-
|
|
72
|
-
Every figure is cited in the code beside what it explains. The complete list is
|
|
73
|
-
[BIBLIOGRAPHY.md](BIBLIOGRAPHY.md).
|
|
74
|
-
|
|
75
|
-
## Example
|
|
76
|
-
|
|
77
17
|
```sh
|
|
78
18
|
npm install tonus
|
|
79
19
|
```
|
|
@@ -92,8 +32,9 @@ const [feast] = tonus.festum({ date: new Date("2026-12-25") });
|
|
|
92
32
|
const [introit] = tonus.proprium({ feast, office: "in" });
|
|
93
33
|
// → "Puer natus est", mode 7, from the Liber Usualis
|
|
94
34
|
|
|
95
|
-
// Turn the chant into tuned, rhythmicized notes.
|
|
35
|
+
// Turn the chant into tuned, rhythmicized notes, then draw it.
|
|
96
36
|
const score = tonus.notatio(introit, { temperamentum: t });
|
|
37
|
+
const { svg, geometry } = tonus.inscriptio(score, { width: 680 });
|
|
97
38
|
|
|
98
39
|
// And voice the Christmas sky as pitch, after Boethius.
|
|
99
40
|
const harmony = tonus.harmonia(tonus.caelum({ date: feast.date }));
|
|
@@ -102,6 +43,56 @@ const harmony = tonus.harmonia(tonus.caelum({ date: feast.date }));
|
|
|
102
43
|
The objects each call returns (`feast`, `t`) pass straight back into the next as
|
|
103
44
|
filters.
|
|
104
45
|
|
|
46
|
+
## The API
|
|
47
|
+
|
|
48
|
+
Fourteen methods, each named for what it returns.
|
|
49
|
+
|
|
50
|
+
| Method | Returns |
|
|
51
|
+
| ----------------------------- | ----------------------------------------------------------------- |
|
|
52
|
+
| `festum({ date })` | the feasts of a day, with rank, grade, and season |
|
|
53
|
+
| `pascha(year)` | Easter and the movable feasts reckoned from it |
|
|
54
|
+
| `cantus({ … })` | chants by id, incipit, mode, office, or source |
|
|
55
|
+
| `proprium({ feast, office })` | the Mass propers for a feast |
|
|
56
|
+
| `ordinarium({ … })` | the Kyriale — the Mass ordinary settings |
|
|
57
|
+
| `officium({ feast, hora })` | an Office hour, psalms and antiphons in order |
|
|
58
|
+
| `psalmus({ psalm })` | a psalm, pointed for its tone |
|
|
59
|
+
| `corpus()` | what ships: counts by book, genus, and mode |
|
|
60
|
+
| `census({ id })` | one chant measured against the corpus |
|
|
61
|
+
| `temperamentum({ … })` | a tuning — `nota`, `gradus`, `modus`, `intervallum` |
|
|
62
|
+
| `notatio(chant)` | GABC parsed to phrases, syllables, and tuned notes |
|
|
63
|
+
| `inscriptio(score)` | `{ svg, geometry }` — the score drawn, and where each note landed |
|
|
64
|
+
| `caelum({ date })` | the classical planets at a moment |
|
|
65
|
+
| `harmonia(caelum)` | those positions voiced as pitch |
|
|
66
|
+
|
|
67
|
+
**Tuning** covers Pythagorean and meantone temperaments, just intonation and
|
|
68
|
+
custom scales, the Guidonian gamut and hand, hexachords and their mutations,
|
|
69
|
+
and intervals named as the treatises name them. Each of the eight modes carries
|
|
70
|
+
its final, dominant, ambitus, and ethos, with its psalm tones.
|
|
71
|
+
|
|
72
|
+
**The calendar** is Tridentine, resolved against Easter by
|
|
73
|
+
the Julian or the Gregorian computus.
|
|
74
|
+
|
|
75
|
+
**The repertoire** is 2,187 chants across ten books — nine Solesmes editions and
|
|
76
|
+
the _Nocturnale Romanum_ night office — in
|
|
77
|
+
[GABC](https://gregorio-project.github.io/) notation: Mass propers, the Kyriale,
|
|
78
|
+
the Office hours, the psalter, and the Matins nocturns.
|
|
79
|
+
|
|
80
|
+
**Scores** are shaped by the Solesmes arsis/thesis rhythm, fingerprinted for
|
|
81
|
+
melodic character, and drawn to a square-note or modern staff.
|
|
82
|
+
|
|
83
|
+
## Concepts
|
|
84
|
+
|
|
85
|
+
Boethius treated music as a branch of number theory, and divided it into the
|
|
86
|
+
audible and the inaudible: instruments and voices, body and soul, the turning
|
|
87
|
+
cosmos. Chant
|
|
88
|
+
was composed inside that frame: pitch was ratio, the modes a received order,
|
|
89
|
+
the heavens harmonic proportion. tonus takes those claims literally enough to
|
|
90
|
+
compute them, which is why tuning is ratio arithmetic, why the calendar is a
|
|
91
|
+
retrieval index, and why there is an ephemeris in a chant library at all.
|
|
92
|
+
|
|
93
|
+
Where the sources run out or contradict one another, tonus makes an editorial
|
|
94
|
+
call and records it in the code.
|
|
95
|
+
|
|
105
96
|
## Documentation
|
|
106
97
|
|
|
107
98
|
The **[documentation index](docs/api/index.md)** is the technical center: the full
|
|
@@ -114,8 +105,7 @@ one page per engine, in dependency order:
|
|
|
114
105
|
## Install and run
|
|
115
106
|
|
|
116
107
|
ESM only. Node ≥ 20; works in the browser through a bundler. No runtime
|
|
117
|
-
dependencies.
|
|
118
|
-
package.
|
|
108
|
+
dependencies. The chants and the 650-entry calendar ship in the package.
|
|
119
109
|
|
|
120
110
|
```sh
|
|
121
111
|
npm test # builds and runs the suite (node --test)
|
|
@@ -124,6 +114,20 @@ npm test # builds and runs the suite (node --test)
|
|
|
124
114
|
The data files in `src/data/` are generated by a separate extraction pipeline
|
|
125
115
|
(tonus-corpus). Edits happen there, not here.
|
|
126
116
|
|
|
117
|
+
## Sources
|
|
118
|
+
|
|
119
|
+
The chant and calendar data are the Solesmes editions, by way of
|
|
120
|
+
[GregoBase](https://gregobase.selapa.net/),
|
|
121
|
+
[Divinum Officium](https://divinumofficium.com/), and the community _Nocturnale
|
|
122
|
+
Romanum_. The notation is engraved in Daniel Spreadbury's
|
|
123
|
+
[Bravura](https://github.com/steinbergmedia/bravura), the reference font for the
|
|
124
|
+
SMuFL standard. Behind the rest stand Mocquereau and Suñol on rhythm, Rockstro
|
|
125
|
+
and Apel on the modes, Boethius and Ptolemy on tuning, and Godwin on the
|
|
126
|
+
Pythagorean planets.
|
|
127
|
+
|
|
128
|
+
Every figure is cited in the code beside what it explains, and
|
|
129
|
+
[BIBLIOGRAPHY.md](BIBLIOGRAPHY.md) is the complete list.
|
|
130
|
+
|
|
127
131
|
## License
|
|
128
132
|
|
|
129
133
|
[PolyForm Noncommercial 1.0.0](LICENSE): free to use, study, modify, and
|
package/dist/data/gabc-glyphs.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
// Codepoints and pitch positions mirror the gabc-smufl project's
|
|
5
5
|
// data/gabc-map.json (SMuFL 1.5 / Bravura 1.392). Outlines for these codepoints
|
|
6
|
-
// are baked into smufl-glyphs.json by scripts/extract-smufl-glyphs.
|
|
6
|
+
// are baked into smufl-glyphs.json by scripts/extract-smufl-glyphs.mjs.
|
|
7
7
|
//
|
|
8
8
|
// pitch_positions: the raw GABC pitch letter a–m IS the staff slot, in
|
|
9
9
|
// half-staff-spaces from the bottom line, independent of clef. (a=-2 … c=0
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// data/smufl-glyphs — SMuFL chant glyph outlines (baked from Bravura)
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
|
-
// Generated by
|
|
4
|
+
// Generated by `npm run glyphs` — do not edit smufl-glyphs.json
|
|
5
5
|
// by hand. Paths are in font units, y-up (baseline at 0); the SVG emitter
|
|
6
6
|
// applies scale(s, -s). See the script header for the coordinate contract.
|
|
7
7
|
|
|
8
8
|
const data = ({
|
|
9
9
|
"meta": {
|
|
10
10
|
"source": "Bravura.otf (Steinberg Media, SIL OFL 1.1)",
|
|
11
|
-
"smufl": "plainchant PUA (U+E8F0
|
|
11
|
+
"smufl": "plainchant PUA (U+E8F0–U+E9D9)",
|
|
12
12
|
"upm": 1000,
|
|
13
13
|
"coordinates": "font units, y-up (baseline at 0); emitter applies scale(s, -s)",
|
|
14
|
-
"regenerate": "
|
|
14
|
+
"regenerate": "npm run glyphs",
|
|
15
15
|
"count": 138
|
|
16
16
|
},
|
|
17
17
|
"glyphs": {
|
|
@@ -1275,7 +1275,7 @@ const data = ({
|
|
|
1275
1275
|
"advance": 215,
|
|
1276
1276
|
"bbox": [
|
|
1277
1277
|
0,
|
|
1278
|
-
-173.
|
|
1278
|
+
-173.08333333333331,
|
|
1279
1279
|
215,
|
|
1280
1280
|
435
|
|
1281
1281
|
]
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"source": "Bravura.otf (Steinberg Media, SIL OFL 1.1)",
|
|
4
|
-
"smufl": "plainchant PUA (U+E8F0
|
|
4
|
+
"smufl": "plainchant PUA (U+E8F0–U+E9D9)",
|
|
5
5
|
"upm": 1000,
|
|
6
6
|
"coordinates": "font units, y-up (baseline at 0); emitter applies scale(s, -s)",
|
|
7
|
-
"regenerate": "
|
|
7
|
+
"regenerate": "npm run glyphs",
|
|
8
8
|
"count": 138
|
|
9
9
|
},
|
|
10
10
|
"glyphs": {
|
|
@@ -1268,7 +1268,7 @@
|
|
|
1268
1268
|
"advance": 215,
|
|
1269
1269
|
"bbox": [
|
|
1270
1270
|
0,
|
|
1271
|
-
-173.
|
|
1271
|
+
-173.08333333333331,
|
|
1272
1272
|
215,
|
|
1273
1273
|
435
|
|
1274
1274
|
]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { BodyName } from "../../planet/types.js";
|
|
2
|
+
/** The four Aristotelian elements, as the triplicities assign them. */
|
|
3
|
+
export type Element = "fire" | "earth" | "air" | "water";
|
|
4
|
+
/** Ptolemy's quadruplicities, in the scholastic naming. */
|
|
5
|
+
export type Quality = "cardinal" | "fixed" | "mutable";
|
|
6
|
+
/** The Galenic humor the sign's element carries. */
|
|
7
|
+
export type Humor = "cholera" | "melancholia" | "sanguis" | "phlegma";
|
|
8
|
+
/** The part of the body a sign governs, in the zodiac man. */
|
|
9
|
+
export interface Melothesia {
|
|
10
|
+
/** The member as the manuscripts name it: caput, collum, pectus… */
|
|
11
|
+
latin: string;
|
|
12
|
+
/** What that covers, in English — several signs govern more than one part. */
|
|
13
|
+
english: string;
|
|
14
|
+
}
|
|
15
|
+
/** A sign's doctrine. English keys carry machine codes; the Latin fields carry
|
|
16
|
+
* the authentic terms a reader meets on the page. */
|
|
17
|
+
export interface ZodiacSign {
|
|
18
|
+
/** 0 = Aries … 11 = Pisces, matching `Body.zodiac`. */
|
|
19
|
+
index: number;
|
|
20
|
+
/** Matches `Body.sign` verbatim. */
|
|
21
|
+
sign: string;
|
|
22
|
+
/** Matches `Body.signum` verbatim — Scorpius, Capricornus. */
|
|
23
|
+
signum: string;
|
|
24
|
+
/** The astronomical symbol, U+2648–U+2653. */
|
|
25
|
+
symbol: string;
|
|
26
|
+
element: Element;
|
|
27
|
+
elementum: string;
|
|
28
|
+
quality: Quality;
|
|
29
|
+
qualitas: string;
|
|
30
|
+
/** The sign's nature as the two Aristotelian pairs, in Latin. */
|
|
31
|
+
nature: {
|
|
32
|
+
heat: string;
|
|
33
|
+
moisture: string;
|
|
34
|
+
};
|
|
35
|
+
genus: "masculinum" | "femininum";
|
|
36
|
+
humor: Humor;
|
|
37
|
+
temperament: string;
|
|
38
|
+
/** The planet that rules the sign. */
|
|
39
|
+
domicile: BodyName;
|
|
40
|
+
/** The planet exalted in it — null for the five that have none. */
|
|
41
|
+
exaltation: BodyName | null;
|
|
42
|
+
melothesia: Melothesia;
|
|
43
|
+
/** Where the sources disagree, said plainly rather than resolved. */
|
|
44
|
+
variant?: string;
|
|
45
|
+
}
|
|
46
|
+
export declare const ZODIACA: readonly ZodiacSign[];
|
|
47
|
+
//# sourceMappingURL=zodiac.d.ts.map
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// engines/harmonia/data/zodiac — what the twelve signs MEAN
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// `caelum` answers WHERE: a body's ecliptic longitude becomes `zodiac` (the
|
|
6
|
+
// index), `sign` and `signum`. This table answers WHAT IT MEANS — the doctrine
|
|
7
|
+
// a medieval reader brought to that position.
|
|
8
|
+
//
|
|
9
|
+
// DELIBERATELY NO DATES. When the Sun enters a sign is the ephemeris's
|
|
10
|
+
// business and changes with precession; a table that carried "March 21" would
|
|
11
|
+
// be wrong for most of the period this library models, and wrong differently
|
|
12
|
+
// every century. The index is the join, and `caelum` computes it.
|
|
13
|
+
//
|
|
14
|
+
// The join: `SIGNS[i]`, `SIGNA[i]` (engines/planet/planet.ts) and `ZODIACA[i]`
|
|
15
|
+
// are one list three ways, so `ZODIACA[body.zodiac]` is always that body's
|
|
16
|
+
// doctrine. The two name arrays live with the ephemeris because drawing the
|
|
17
|
+
// wheel needs them without any of this; the meanings live here because nothing
|
|
18
|
+
// in computing a position depends on them.
|
|
19
|
+
//
|
|
20
|
+
// Sources, per field:
|
|
21
|
+
// domicile Ptolemy, Tetrabiblos I.17 [biblio: ptolemy-tetrabiblos],
|
|
22
|
+
// transmitted whole through the medieval Latin tradition and
|
|
23
|
+
// uncontested across sources.
|
|
24
|
+
// exaltation Tetrabiblos I.19 and the standard medieval list, THE SEVEN
|
|
25
|
+
// PLANETS ONLY. The lunar nodes' exaltations (Caput Draconis in
|
|
26
|
+
// Gemini, Cauda in Sagittarius) are omitted because the nodes are
|
|
27
|
+
// not tonus bodies. The exaltation DEGREES (Sun at 19° Arietis
|
|
28
|
+
// and the rest) are omitted as more precision than any consumer
|
|
29
|
+
// here reads — five signs simply have no exaltation, and that
|
|
30
|
+
// absence is the tradition's, not an omission.
|
|
31
|
+
// element, the Ptolemaic triplicities and quadruplicities. The Latin
|
|
32
|
+
// quality quality terms are the scholastic mobile/fixum/commune, where
|
|
33
|
+
// Ptolemy writes tropic/solid/bicorporeal.
|
|
34
|
+
// humor the Galenic element→humor square — fire/cholera, earth/
|
|
35
|
+
// melancholia, air/sanguis, water/phlegma — ubiquitous in
|
|
36
|
+
// medieval medicine.
|
|
37
|
+
// melothesia the homo signorum of medieval calendars and medical
|
|
38
|
+
// manuscripts, Aries at the head down to Pisces at the feet (the
|
|
39
|
+
// Très Riches Heures anatomical man is the familiar picture).
|
|
40
|
+
// Practice, not decoration: phlebotomy was timed against it.
|
|
41
|
+
//
|
|
42
|
+
// Where the tradition wobbles, the entry says so in `variant` rather than
|
|
43
|
+
// picking a winner quietly. Uncertainty is data.
|
|
44
|
+
export const ZODIACA = [
|
|
45
|
+
{
|
|
46
|
+
index: 0, sign: "Aries", signum: "Aries", symbol: "♈",
|
|
47
|
+
element: "fire", elementum: "ignis",
|
|
48
|
+
quality: "cardinal", qualitas: "mobile",
|
|
49
|
+
nature: { heat: "calidum", moisture: "siccum" },
|
|
50
|
+
genus: "masculinum", humor: "cholera", temperament: "cholericum",
|
|
51
|
+
domicile: "Mars", exaltation: "Sun",
|
|
52
|
+
melothesia: { latin: "caput", english: "the head and face" },
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
index: 1, sign: "Taurus", signum: "Taurus", symbol: "♉",
|
|
56
|
+
element: "earth", elementum: "terra",
|
|
57
|
+
quality: "fixed", qualitas: "fixum",
|
|
58
|
+
nature: { heat: "frigidum", moisture: "siccum" },
|
|
59
|
+
genus: "femininum", humor: "melancholia", temperament: "melancholicum",
|
|
60
|
+
domicile: "Venus", exaltation: "Moon",
|
|
61
|
+
melothesia: { latin: "collum", english: "the neck and throat" },
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
index: 2, sign: "Gemini", signum: "Gemini", symbol: "♊",
|
|
65
|
+
element: "air", elementum: "aer",
|
|
66
|
+
quality: "mutable", qualitas: "commune",
|
|
67
|
+
nature: { heat: "calidum", moisture: "humidum" },
|
|
68
|
+
genus: "masculinum", humor: "sanguis", temperament: "sanguineum",
|
|
69
|
+
domicile: "Mercury", exaltation: null,
|
|
70
|
+
melothesia: { latin: "umeri", english: "the shoulders, arms and hands" },
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
index: 3, sign: "Cancer", signum: "Cancer", symbol: "♋",
|
|
74
|
+
element: "water", elementum: "aqua",
|
|
75
|
+
quality: "cardinal", qualitas: "mobile",
|
|
76
|
+
nature: { heat: "frigidum", moisture: "humidum" },
|
|
77
|
+
genus: "femininum", humor: "phlegma", temperament: "phlegmaticum",
|
|
78
|
+
domicile: "Moon", exaltation: "Jupiter",
|
|
79
|
+
melothesia: { latin: "pectus", english: "the breast and chest" },
|
|
80
|
+
variant: "the melothesia wobbles here more than anywhere: some manuscripts "
|
|
81
|
+
+ "extend Cancer to the lungs and stomach",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
index: 4, sign: "Leo", signum: "Leo", symbol: "♌",
|
|
85
|
+
element: "fire", elementum: "ignis",
|
|
86
|
+
quality: "fixed", qualitas: "fixum",
|
|
87
|
+
nature: { heat: "calidum", moisture: "siccum" },
|
|
88
|
+
genus: "masculinum", humor: "cholera", temperament: "cholericum",
|
|
89
|
+
domicile: "Sun", exaltation: null,
|
|
90
|
+
melothesia: { latin: "cor", english: "the heart, back and sides" },
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
index: 5, sign: "Virgo", signum: "Virgo", symbol: "♍",
|
|
94
|
+
element: "earth", elementum: "terra",
|
|
95
|
+
quality: "mutable", qualitas: "commune",
|
|
96
|
+
nature: { heat: "frigidum", moisture: "siccum" },
|
|
97
|
+
genus: "femininum", humor: "melancholia", temperament: "melancholicum",
|
|
98
|
+
domicile: "Mercury", exaltation: "Mercury",
|
|
99
|
+
melothesia: { latin: "venter", english: "the belly and bowels" },
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
index: 6, sign: "Libra", signum: "Libra", symbol: "♎",
|
|
103
|
+
element: "air", elementum: "aer",
|
|
104
|
+
quality: "cardinal", qualitas: "mobile",
|
|
105
|
+
nature: { heat: "calidum", moisture: "humidum" },
|
|
106
|
+
genus: "masculinum", humor: "sanguis", temperament: "sanguineum",
|
|
107
|
+
domicile: "Venus", exaltation: "Saturn",
|
|
108
|
+
melothesia: { latin: "renes", english: "the kidneys and loins" },
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
index: 7, sign: "Scorpio", signum: "Scorpius", symbol: "♏",
|
|
112
|
+
element: "water", elementum: "aqua",
|
|
113
|
+
quality: "fixed", qualitas: "fixum",
|
|
114
|
+
nature: { heat: "frigidum", moisture: "humidum" },
|
|
115
|
+
genus: "femininum", humor: "phlegma", temperament: "phlegmaticum",
|
|
116
|
+
domicile: "Mars", exaltation: null,
|
|
117
|
+
melothesia: { latin: "genitalia", english: "the genitals" },
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
index: 8, sign: "Sagittarius", signum: "Sagittarius", symbol: "♐",
|
|
121
|
+
element: "fire", elementum: "ignis",
|
|
122
|
+
quality: "mutable", qualitas: "commune",
|
|
123
|
+
nature: { heat: "calidum", moisture: "siccum" },
|
|
124
|
+
genus: "masculinum", humor: "cholera", temperament: "cholericum",
|
|
125
|
+
domicile: "Jupiter", exaltation: null,
|
|
126
|
+
melothesia: { latin: "femora", english: "the thighs" },
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
index: 9, sign: "Capricorn", signum: "Capricornus", symbol: "♑",
|
|
130
|
+
element: "earth", elementum: "terra",
|
|
131
|
+
quality: "cardinal", qualitas: "mobile",
|
|
132
|
+
nature: { heat: "frigidum", moisture: "siccum" },
|
|
133
|
+
genus: "femininum", humor: "melancholia", temperament: "melancholicum",
|
|
134
|
+
domicile: "Saturn", exaltation: "Mars",
|
|
135
|
+
melothesia: { latin: "genua", english: "the knees" },
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
index: 10, sign: "Aquarius", signum: "Aquarius", symbol: "♒",
|
|
139
|
+
element: "air", elementum: "aer",
|
|
140
|
+
quality: "fixed", qualitas: "fixum",
|
|
141
|
+
nature: { heat: "calidum", moisture: "humidum" },
|
|
142
|
+
genus: "masculinum", humor: "sanguis", temperament: "sanguineum",
|
|
143
|
+
domicile: "Saturn", exaltation: null,
|
|
144
|
+
melothesia: { latin: "crura", english: "the shins and ankles" },
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
index: 11, sign: "Pisces", signum: "Pisces", symbol: "♓",
|
|
148
|
+
element: "water", elementum: "aqua",
|
|
149
|
+
quality: "mutable", qualitas: "commune",
|
|
150
|
+
nature: { heat: "frigidum", moisture: "humidum" },
|
|
151
|
+
genus: "femininum", humor: "phlegma", temperament: "phlegmaticum",
|
|
152
|
+
domicile: "Jupiter", exaltation: "Venus",
|
|
153
|
+
melothesia: { latin: "pedes", english: "the feet" },
|
|
154
|
+
},
|
|
155
|
+
];
|
|
156
|
+
// THE LUNAR PROHIBITION, recorded here rather than exported: while the Moon
|
|
157
|
+
// stands in a sign, that sign's member is not to be touched. It is the reason
|
|
158
|
+
// the zodiac man is in a physician's calendar at all — it was "dangerous, if
|
|
159
|
+
// not fatal, to treat that member if the Moon was in the sign at the time" —
|
|
160
|
+
// and it is one line of doctrine that any consumer can state for itself from
|
|
161
|
+
// `ZODIACA[moon.zodiac].melothesia`. A constant holding a sentence of English
|
|
162
|
+
// would be prose pretending to be data.
|
|
163
|
+
//# sourceMappingURL=zodiac.js.map
|
|
@@ -135,7 +135,14 @@ function resolveOpts(o) {
|
|
|
135
135
|
rubricaColor: cssVar("rubrica", o.rubricaColor ?? "#9E2B25"),
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
|
-
|
|
138
|
+
// JUNICODE FIRST, then the Garamonds. tonus ships no font bytes, so this stack
|
|
139
|
+
// is a request and not a guarantee — but naming the recommended face at its
|
|
140
|
+
// head costs nothing and means a page that already loads Junicode (the labs,
|
|
141
|
+
// the site, a medievalist's own stylesheet) gets the dress the plates are drawn
|
|
142
|
+
// with without passing a `fonts` option at all. Every name after it is the
|
|
143
|
+
// fallback that was here before, so a page without Junicode renders exactly as
|
|
144
|
+
// it did. See score.md → "The recommended face".
|
|
145
|
+
const HOUSE_SERIF = "Junicode, 'Crimson Pro', 'Crimson Text', 'EB Garamond', Garamond, Georgia, serif";
|
|
139
146
|
// The books abbreviate the genus in the margin mark (Intr., Grad., Offert.);
|
|
140
147
|
// a genus not in the table prints as-is with its period.
|
|
141
148
|
const GENUS_ABBREV = {
|
package/dist/index.d.ts
CHANGED
|
@@ -56,7 +56,7 @@ export { TONES } from "./engines/temper/data/tones.js";
|
|
|
56
56
|
export type { PsalmTone, Differentia } from "./engines/temper/data/tones.js";
|
|
57
57
|
export { CADENTIAE, CADENTIAE_POPULATION } from "./data/cadentiae.js";
|
|
58
58
|
export type { CadentiaFamilia } from "./data/cadentiae.js";
|
|
59
|
-
export {
|
|
59
|
+
export { ZODIACA } from "./engines/harmonia/data/zodiac.js";
|
|
60
60
|
export { CENSUS_GROUPS, CENSUS_ORDER } from "./data/census.js";
|
|
61
61
|
export type { Feast, FeastQuery, Pascha, Season, Grade, Chant, CantusQuery, OrdinaryChant, PropriumQuery, OrdinariumQuery, OfficiumQuery, PsalmusQuery, Corpus, GenusCount, ModeCount, SharedCount, CorpusLedger, CorpusFullCount, CorpusQuery, Census, CensusQuery, CensusBy, CensusGroup, CensusGroupProfile, CensusNeighbor, Temperamentum, TemperamentumInput, TemperamentumOpts, Tuning, Pitch, PitchInput, Step, Neume, NeumeShape, Interval, ModeData, CadenceFigure, Modus, TunedNote, GamutOptions, Tonus, TonusOpts, Score, ScoreOpts, PondusInput, PondusOpts, AccentusInput, AccentusOpts, Cadence, CadenceTarget, CadenceApproach, Modulation, InscriptioOpts, Inscriptio, NoteGeometry, FontSpec, FontSlot, FontEmbed, ChantTabulaRow, Note, Performance, Phrase, Syllable, LyricRun, RestEvent, ParseError, ArsisThesis, RhythmicType, CompoundBeat, VoicedPitch, Cosmos, CosmosQuery, Body, BodyName, Aspect, Imprint, Attractor, VowelAttractor, ModalAffinity, Prosody, RhythmicProfile, NoteRange, CadenceDistribution, Harmony, HarmoniaOpts, VoicedBody, VoicedAspect, Frame, Author, HarmonyTabulaRow, PlanetVowel, };
|
|
62
62
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -54,8 +54,11 @@ export { SOURCES } from "./engines/chant/chant.js"; // book code → bibliograph
|
|
|
54
54
|
export { MODES } from "./engines/temper/data/modes.js";
|
|
55
55
|
export { TONES } from "./engines/temper/data/tones.js";
|
|
56
56
|
export { CADENTIAE, CADENTIAE_POPULATION } from "./data/cadentiae.js";
|
|
57
|
-
// planet — the zodiac
|
|
58
|
-
|
|
57
|
+
// planet — the zodiac. ZODIACA is the whole table: it carries each sign's own
|
|
58
|
+
// `sign` and `signum` beside its doctrine, so `ZODIACA[body.zodiac]` answers
|
|
59
|
+
// both what the sign is CALLED and what it MEANS. The bare name arrays stay
|
|
60
|
+
// inside the engine that computes a longitude, where they are the lookup.
|
|
61
|
+
export { ZODIACA } from "./engines/harmonia/data/zodiac.js";
|
|
59
62
|
// census — the field groups and the block index. CENSUS_GROUPS keys are the
|
|
60
63
|
// valid `by:` values AND the `profile` keys; CENSUS_ORDER holds every censused
|
|
61
64
|
// id, so asking whether a chant is in the census stops needing a try/catch.
|
package/docs/api/heavens.md
CHANGED
|
@@ -9,6 +9,7 @@ summarized in [Theory & Context](#theory--context).
|
|
|
9
9
|
- [Heavens](#heavens)
|
|
10
10
|
- [The heavens — `caelum`](#the-heavens--caelum)
|
|
11
11
|
- [Aspects](#aspects)
|
|
12
|
+
- [The signs — `ZODIACA`](#the-signs--zodiaca)
|
|
12
13
|
- [The voiced heavens — `harmonia`](#the-voiced-heavens--harmonia)
|
|
13
14
|
- [The planetary vowels](#the-planetary-vowels)
|
|
14
15
|
- [The tabula](#the-tabula)
|
|
@@ -129,6 +130,55 @@ interface Aspect {
|
|
|
129
130
|
}
|
|
130
131
|
```
|
|
131
132
|
|
|
133
|
+
## The signs — `ZODIACA`
|
|
134
|
+
|
|
135
|
+
`caelum` answers WHERE a body is. `ZODIACA` answers what that position MEANT:
|
|
136
|
+
the doctrine a medieval reader brought to a planet standing in a sign.
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
import tonus, { ZODIACA } from "tonus";
|
|
140
|
+
|
|
141
|
+
const [sun] = tonus.caelum({ date: new Date("2026-12-25") }).bodies;
|
|
142
|
+
const sign = ZODIACA[sun.zodiac];
|
|
143
|
+
// → { sign: "Capricorn", signum: "Capricornus", symbol: "♑",
|
|
144
|
+
// element: "earth", elementum: "terra", humor: "melancholia",
|
|
145
|
+
// quality: "cardinal", domicile: "Saturn", exaltation: "Mars",
|
|
146
|
+
// melothesia: { latin: "genua", english: "the knees" }, … }
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`ZODIACA[body.zodiac]` is the join. The array is in ecliptic order and each
|
|
150
|
+
entry knows its own `index`, so a body's sign is addressed directly rather than
|
|
151
|
+
searched for.
|
|
152
|
+
|
|
153
|
+
| Field | What it holds |
|
|
154
|
+
| ----------------------- | -------------------------------------------------------------------- |
|
|
155
|
+
| `sign` / `signum` | the code and the Latin — identical to `Body.sign` / `Body.signum` |
|
|
156
|
+
| `symbol` | the astronomical sign, U+2648–U+2653 |
|
|
157
|
+
| `element` / `elementum` | one of the four, and its Latin |
|
|
158
|
+
| `quality` / `qualitas` | cardinal, fixed, mutable — Ptolemy's tropic/solid/bicorporeal |
|
|
159
|
+
| `nature` | the two Aristotelian pairs: `calidum`/`frigidum`, `siccum`/`humidum` |
|
|
160
|
+
| `humor` / `temperament` | the Galenic humor the element carries, and its temperament |
|
|
161
|
+
| `domicile` | the planet that rules the sign, as a `BodyName` |
|
|
162
|
+
| `exaltation` | the planet exalted in it — `null` for the five that have none |
|
|
163
|
+
| `melothesia` | the member of the zodiac man the sign governs |
|
|
164
|
+
| `variant` | present only where the sources disagree |
|
|
165
|
+
|
|
166
|
+
**There are no dates.** When the Sun enters a sign is the ephemeris's business
|
|
167
|
+
and moves with precession; a table carrying "March 21" would be wrong for most
|
|
168
|
+
of the period this library models, and wrong differently every century.
|
|
169
|
+
|
|
170
|
+
**What is omitted, and why.** The exaltation degrees Ptolemy gives (the Sun at
|
|
171
|
+
19° Arietis and the rest) are not carried — the sign is the resolution anything
|
|
172
|
+
here reads. Nor are the lunar nodes' exaltations, because the nodes are not
|
|
173
|
+
tonus bodies. Five signs exalt nobody: that silence is the tradition's, not a
|
|
174
|
+
gap in the table.
|
|
175
|
+
|
|
176
|
+
The `melothesia` is the *homo signorum* of medieval calendars — Aries at the
|
|
177
|
+
head down to Pisces at the feet. It was practice, not decoration: phlebotomy
|
|
178
|
+
was timed against it, and while the Moon stood in a sign its member was not to
|
|
179
|
+
be touched. Sourced from Ptolemy's *Tetrabiblos* I.17 and I.19
|
|
180
|
+
[biblio: ptolemy-tetrabiblos].
|
|
181
|
+
|
|
132
182
|
## The voiced heavens — `harmonia`
|
|
133
183
|
|
|
134
184
|
`harmonia(cosmos, opts?)` gives each body a pitch and a Greek vowel according to
|
package/docs/api/index.md
CHANGED
|
@@ -4,6 +4,8 @@ The technical center of tonus: the full public API, the conventions every method
|
|
|
4
4
|
obeys, and the error contract. The API is **fourteen methods on the `tonus`
|
|
5
5
|
namespace**, no sub-namespaces.
|
|
6
6
|
|
|
7
|
+
**[Interactive demo →](https://jeffreypierce.github.io/tonus/)**
|
|
8
|
+
|
|
7
9
|
```js
|
|
8
10
|
import tonus from "tonus";
|
|
9
11
|
```
|
|
@@ -15,22 +17,22 @@ import tonus from "tonus";
|
|
|
15
17
|
|
|
16
18
|
## The methods
|
|
17
19
|
|
|
18
|
-
| Method
|
|
19
|
-
|
|
|
20
|
-
| `tonus.festum(query?)`
|
|
21
|
-
| `tonus.pascha(year)`
|
|
22
|
-
| `tonus.cantus(query?)`
|
|
23
|
-
| `tonus.corpus(code?)`
|
|
24
|
-
| `tonus.proprium(query?)`
|
|
25
|
-
| `tonus.ordinarium(query?)`
|
|
26
|
-
| `tonus.officium(query?)`
|
|
27
|
-
| `tonus.psalmus(query?)`
|
|
28
|
-
| `tonus.temperamentum(input?)`
|
|
29
|
-
| `tonus.notatio(chant, opts?)`
|
|
30
|
-
| `tonus.inscriptio(score, opts?)`
|
|
31
|
-
| `tonus.caelum(query?)`
|
|
32
|
-
| `tonus.harmonia(cosmos, opts?)`
|
|
33
|
-
| `tonus.census(query)`
|
|
20
|
+
| Method | Page | Returns |
|
|
21
|
+
| -------------------------------- | ----------------------- | ------------------------------------------------------- |
|
|
22
|
+
| `tonus.festum(query?)` | [calendar](calendar.md) | `Feast[]` — liturgical calendar lookup |
|
|
23
|
+
| `tonus.pascha(year)` | [calendar](calendar.md) | `Pascha` — the movable anchors of a liturgical year |
|
|
24
|
+
| `tonus.cantus(query?)` | [chant](chant.md) | `Chant[]` — cross-corpus chant retrieval / GABC parsing |
|
|
25
|
+
| `tonus.corpus(code?)` | [chant](chant.md) | `Corpus` — a book's ledger; no arg → the whole shelf |
|
|
26
|
+
| `tonus.proprium(query?)` | [chant](chant.md) | `Chant[]` — Mass propers |
|
|
27
|
+
| `tonus.ordinarium(query?)` | [chant](chant.md) | `OrdinaryChant[]` — Kyriale |
|
|
28
|
+
| `tonus.officium(query?)` | [chant](chant.md) | `Chant[]` — Divine Office hours |
|
|
29
|
+
| `tonus.psalmus(query?)` | [chant](chant.md) | `Chant[]` — intoned psalm verses |
|
|
30
|
+
| `tonus.temperamentum(input?)` | [tuning](tuning.md) | `Temperamentum` — tuning context |
|
|
31
|
+
| `tonus.notatio(chant, opts?)` | [score](score.md) | `Score` — GABC → musical score |
|
|
32
|
+
| `tonus.inscriptio(score, opts?)` | [score](score.md) | `Inscriptio` — `{ svg, geometry }`, the score drawn |
|
|
33
|
+
| `tonus.caelum(query?)` | [heavens](heavens.md) | `Cosmos \| Cosmos[]` — ephemeris |
|
|
34
|
+
| `tonus.harmonia(cosmos, opts?)` | [heavens](heavens.md) | `Harmony` — musica universalis |
|
|
35
|
+
| `tonus.census(query)` | [census](census.md) | `Census` — a chant against the corpus |
|
|
34
36
|
|
|
35
37
|
### Query and builder functions
|
|
36
38
|
|
package/docs/api/score.md
CHANGED
|
@@ -446,6 +446,39 @@ files: with `embed` it is a conduit for data the consumer supplies, so the
|
|
|
446
446
|
consumer carries the face's license terms. Unset roles keep the house serif.
|
|
447
447
|
`moderna` honours the `lyric`, `title`, and `annotation` slots.
|
|
448
448
|
|
|
449
|
+
#### The recommended face — Junicode
|
|
450
|
+
|
|
451
|
+
The plates are drawn in
|
|
452
|
+
**[Junicode](https://github.com/psb1558/Junicode-font)** (OFL), which the house
|
|
453
|
+
stack already asks for first. Load it and add the dress:
|
|
454
|
+
|
|
455
|
+
```css
|
|
456
|
+
@font-face {
|
|
457
|
+
font-family: "Junicode";
|
|
458
|
+
src: url("JunicodeVF-Roman.woff2") format("woff2-variations");
|
|
459
|
+
font-weight: 300 700;
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
```js
|
|
464
|
+
tonus.inscriptio(score, {
|
|
465
|
+
width: 900,
|
|
466
|
+
theme: {
|
|
467
|
+
fonts: {
|
|
468
|
+
dropcap: { family: "Junicode", weight: 700 },
|
|
469
|
+
title: { family: "Junicode", weight: 620 },
|
|
470
|
+
annotation: { family: "Junicode", weight: 640 },
|
|
471
|
+
lyric: { family: "Junicode", weight: 560, scale: 1.06 },
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
dropcap: true, annotation: "auto", // a role shows only once its feature is on
|
|
475
|
+
});
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
Reference it rather than `embed` it unless one SVG must travel alone: the face
|
|
479
|
+
is 196 KB base64'd, which triples a typical chant and repeats in every file,
|
|
480
|
+
where a reference is cached once.
|
|
481
|
+
|
|
449
482
|
**`colors`** reach the SVG as CSS custom properties with the theme's own value
|
|
450
483
|
as the fallback — `fill="var(--tonus-note, #111)"`. A rendered chant therefore
|
|
451
484
|
carries the ink it was drawn with *and* stays themable: a host stylesheet that
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tonus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Medieval music analysis and performance: GABC plainchant exports, liturgical calendar, tuning systems, ephemeris, and the harmony of the spheres",
|
|
6
6
|
"author": "Jeffrey Pierce <jeffrey@jeffreypierce.net>",
|
|
@@ -55,10 +55,12 @@
|
|
|
55
55
|
"serve": "npm run site && node scripts/serve.mjs",
|
|
56
56
|
"diagrams": "npm run site && node scripts/diagram-lab.mjs",
|
|
57
57
|
"lab": "npm run build && node scripts/render-lab.mjs",
|
|
58
|
-
"stress": "npm run build && node scripts/render-stress.mjs"
|
|
58
|
+
"stress": "npm run build && node scripts/render-stress.mjs",
|
|
59
|
+
"glyphs": "node scripts/extract-smufl-glyphs.mjs"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
62
|
"@types/node": "^22.0.0",
|
|
63
|
+
"fontkit": "^2.0.0",
|
|
62
64
|
"typescript": "^5.6.3"
|
|
63
65
|
},
|
|
64
66
|
"engines": {
|