magick-components 0.0.0-stage → 0.1.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.txt +89 -0
- package/README.md +353 -2
- package/fonts/FrankRuhlLibre-Bold-letters.woff2 +0 -0
- package/fonts/FrankRuhlLibre-OFL.txt +105 -0
- package/fonts/NotoSerif-BoldItalic-compass.woff2 +0 -0
- package/fonts/NotoSerif-Italic-latin1.woff2 +0 -0
- package/fonts/NotoSerif-OFL.txt +93 -0
- package/fonts/SOURCES.md +35 -0
- package/fonts/gd-hall.css +3 -0
- package/lib/astrology/Kamea.d.ts +75 -0
- package/lib/astrology/Kamea.js +73 -0
- package/lib/astrology/MercuryWidget.d.ts +21 -0
- package/lib/astrology/MercuryWidget.js +80 -0
- package/lib/astrology/Moon.d.ts +32 -0
- package/lib/astrology/Moon.js +39 -0
- package/lib/astrology/MoonWidget.d.ts +20 -0
- package/lib/astrology/MoonWidget.js +63 -0
- package/lib/astrology/PlanetarySpirit.d.ts +103 -0
- package/lib/astrology/PlanetarySpirit.js +102 -0
- package/lib/astrology/mercuryRetrograde.d.ts +20 -0
- package/lib/astrology/mercuryRetrograde.js +80 -0
- package/lib/astrology/moonPath.d.ts +20 -0
- package/lib/astrology/moonPath.js +45 -0
- package/lib/chakras/Chakras.d.ts +34 -0
- package/lib/chakras/Chakras.js +149 -0
- package/lib/cssString.d.ts +5 -0
- package/lib/cssString.js +7 -0
- package/lib/drawingVersions.d.ts +29 -0
- package/lib/drawingVersions.js +15 -0
- package/lib/enochian/Tablet.d.ts +17 -0
- package/lib/enochian/Tablet.js +24 -0
- package/lib/enochian/tabletSigils.d.ts +46 -0
- package/lib/enochian/tabletSigils.js +172 -0
- package/lib/enochian/tabletSvg.d.ts +85 -0
- package/lib/enochian/tabletSvg.js +278 -0
- package/lib/gd/FylfotCross.d.ts +60 -0
- package/lib/gd/FylfotCross.js +121 -0
- package/lib/gd/GradeTree.d.ts +10 -0
- package/lib/gd/GradeTree.js +21 -0
- package/lib/gd/Lamen.d.ts +31 -0
- package/lib/gd/Lamen.js +317 -0
- package/lib/gd/RoseSigil.d.ts +31 -0
- package/lib/gd/RoseSigil.js +49 -0
- package/lib/gd/RoseSigilImage.d.ts +38 -0
- package/lib/gd/RoseSigilImage.js +29 -0
- package/lib/gd/SevenBranchedCandlestick.d.ts +54 -0
- package/lib/gd/SevenBranchedCandlestick.js +269 -0
- package/lib/gd/TableOfShewbread.d.ts +19 -0
- package/lib/gd/TableOfShewbread.js +120 -0
- package/lib/gd/hall/GdHall.d.ts +94 -0
- package/lib/gd/hall/GdHall.js +147 -0
- package/lib/gd/hall/art/altar.d.ts +8 -0
- package/lib/gd/hall/art/altar.js +21 -0
- package/lib/gd/hall/art/altarItems.d.ts +20 -0
- package/lib/gd/hall/art/altarItems.js +113 -0
- package/lib/gd/hall/art/banner.d.ts +23 -0
- package/lib/gd/hall/art/banner.js +64 -0
- package/lib/gd/hall/art/board.d.ts +9 -0
- package/lib/gd/hall/art/board.js +49 -0
- package/lib/gd/hall/art/cards.d.ts +11 -0
- package/lib/gd/hall/art/cards.js +124 -0
- package/lib/gd/hall/art/furnishings.d.ts +12 -0
- package/lib/gd/hall/art/furnishings.js +36 -0
- package/lib/gd/hall/art/geometry.d.ts +49 -0
- package/lib/gd/hall/art/geometry.js +97 -0
- package/lib/gd/hall/art/hebrewLetter.d.ts +10 -0
- package/lib/gd/hall/art/hebrewLetter.js +38 -0
- package/lib/gd/hall/art/index.d.ts +7 -0
- package/lib/gd/hall/art/index.js +61 -0
- package/lib/gd/hall/art/items.d.ts +12 -0
- package/lib/gd/hall/art/items.js +125 -0
- package/lib/gd/hall/art/kamea.d.ts +20 -0
- package/lib/gd/hall/art/kamea.js +64 -0
- package/lib/gd/hall/art/lamen.d.ts +9 -0
- package/lib/gd/hall/art/lamen.js +52 -0
- package/lib/gd/hall/art/lightning.d.ts +13 -0
- package/lib/gd/hall/art/lightning.js +44 -0
- package/lib/gd/hall/art/lights.d.ts +13 -0
- package/lib/gd/hall/art/lights.js +64 -0
- package/lib/gd/hall/art/marker.d.ts +8 -0
- package/lib/gd/hall/art/marker.js +19 -0
- package/lib/gd/hall/art/pantacle.d.ts +10 -0
- package/lib/gd/hall/art/pantacle.js +119 -0
- package/lib/gd/hall/art/pillar.d.ts +4 -0
- package/lib/gd/hall/art/pillar.js +25 -0
- package/lib/gd/hall/art/placeholder.d.ts +8 -0
- package/lib/gd/hall/art/placeholder.js +18 -0
- package/lib/gd/hall/art/platform.d.ts +13 -0
- package/lib/gd/hall/art/platform.js +28 -0
- package/lib/gd/hall/art/seals.d.ts +23 -0
- package/lib/gd/hall/art/seals.js +151 -0
- package/lib/gd/hall/art/shared.d.ts +87 -0
- package/lib/gd/hall/art/shared.js +95 -0
- package/lib/gd/hall/art/symbols.d.ts +37 -0
- package/lib/gd/hall/art/symbols.js +134 -0
- package/lib/gd/hall/art/tarotKey.d.ts +34 -0
- package/lib/gd/hall/art/tarotKey.js +101 -0
- package/lib/gd/hall/art/veil.d.ts +8 -0
- package/lib/gd/hall/art/veil.js +22 -0
- package/lib/gd/hall/art/vessels.d.ts +19 -0
- package/lib/gd/hall/art/vessels.js +74 -0
- package/lib/gd/hall/aspect.d.ts +31 -0
- package/lib/gd/hall/aspect.js +161 -0
- package/lib/gd/hall/attributes.d.ts +52 -0
- package/lib/gd/hall/attributes.js +116 -0
- package/lib/gd/hall/describe.d.ts +38 -0
- package/lib/gd/hall/describe.js +184 -0
- package/lib/gd/hall/dimensions.d.ts +39 -0
- package/lib/gd/hall/dimensions.js +49 -0
- package/lib/gd/hall/editor.d.ts +13 -0
- package/lib/gd/hall/editor.js +13 -0
- package/lib/gd/hall/fontMetrics.json +177 -0
- package/lib/gd/hall/fonts.d.ts +45 -0
- package/lib/gd/hall/fonts.js +73 -0
- package/lib/gd/hall/hebrewLetters.d.ts +8 -0
- package/lib/gd/hall/hebrewLetters.js +40 -0
- package/lib/gd/hall/index.d.ts +19 -0
- package/lib/gd/hall/index.js +17 -0
- package/lib/gd/hall/labels.d.ts +72 -0
- package/lib/gd/hall/labels.js +109 -0
- package/lib/gd/hall/layout.d.ts +213 -0
- package/lib/gd/hall/layout.js +837 -0
- package/lib/gd/hall/planets.d.ts +13 -0
- package/lib/gd/hall/planets.js +35 -0
- package/lib/gd/hall/presets/index.d.ts +13 -0
- package/lib/gd/hall/presets/index.js +29 -0
- package/lib/gd/hall/presets/neophyte.d.ts +7 -0
- package/lib/gd/hall/presets/neophyte.js +74 -0
- package/lib/gd/hall/presets/philosophus.d.ts +30 -0
- package/lib/gd/hall/presets/philosophus.js +244 -0
- package/lib/gd/hall/presets/portal.d.ts +24 -0
- package/lib/gd/hall/presets/portal.js +241 -0
- package/lib/gd/hall/presets/practicus.d.ts +17 -0
- package/lib/gd/hall/presets/practicus.js +181 -0
- package/lib/gd/hall/presets/theoricus.d.ts +13 -0
- package/lib/gd/hall/presets/theoricus.js +178 -0
- package/lib/gd/hall/presets/types.d.ts +72 -0
- package/lib/gd/hall/presets/types.js +58 -0
- package/lib/gd/hall/presets/zelator.d.ts +12 -0
- package/lib/gd/hall/presets/zelator.js +161 -0
- package/lib/gd/hall/spec.d.ts +54 -0
- package/lib/gd/hall/spec.js +108 -0
- package/lib/gd/hall/types.d.ts +131 -0
- package/lib/gd/hall/types.js +1 -0
- package/lib/gd/hall/validate.d.ts +13 -0
- package/lib/gd/hall/validate.js +285 -0
- package/lib/gd/hall/vocabulary.d.ts +139 -0
- package/lib/gd/hall/vocabulary.js +435 -0
- package/lib/gd/lamenGlyphs.d.ts +16 -0
- package/lib/gd/lamenGlyphs.js +167 -0
- package/lib/gd/lamenGrades.d.ts +29 -0
- package/lib/gd/lamenGrades.js +36 -0
- package/lib/gd/roseSigilGeometry.d.ts +10 -0
- package/lib/gd/roseSigilGeometry.js +10 -0
- package/lib/gd/roseSigilInternals.d.ts +85 -0
- package/lib/gd/roseSigilInternals.js +343 -0
- package/lib/gd/roseSigilOptimizer.d.ts +15 -0
- package/lib/gd/roseSigilOptimizer.js +59 -0
- package/lib/gd/roseSigilVersions.d.ts +12 -0
- package/lib/gd/roseSigilVersions.js +57 -0
- package/lib/hooks/useHydrated.d.ts +9 -0
- package/lib/hooks/useHydrated.js +13 -0
- package/lib/kabbalah/TreeOfLife.d.ts +135 -0
- package/lib/kabbalah/TreeOfLife.js +312 -0
- package/lib/kabbalah/fieldPath.d.ts +25 -0
- package/lib/kabbalah/fieldPath.js +100 -0
- package/lib/kabbalah/treeLabels.d.ts +30 -0
- package/lib/kabbalah/treeLabels.js +32 -0
- package/lib/kabbalah/treeOfLifeFigure.d.ts +59 -0
- package/lib/kabbalah/treeOfLifeFigure.js +151 -0
- package/lib/svgCoordinate.d.ts +12 -0
- package/lib/svgCoordinate.js +16 -0
- package/package.json +162 -3
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import elements from "magick-data/alchemy/elements";
|
|
3
|
+
import planets from "magick-data/astrology/planets";
|
|
4
|
+
import zodiac from "magick-data/astrology/zodiac";
|
|
5
|
+
const colorFromElement = {
|
|
6
|
+
fire: "red",
|
|
7
|
+
water: "blue",
|
|
8
|
+
air: "yellow",
|
|
9
|
+
earth: "#333",
|
|
10
|
+
};
|
|
11
|
+
const flashingColorFromColor = {
|
|
12
|
+
red: "green",
|
|
13
|
+
blue: "yellow",
|
|
14
|
+
yellow: "purple",
|
|
15
|
+
"#333": "red",
|
|
16
|
+
};
|
|
17
|
+
function elementFromPos(row, col) {
|
|
18
|
+
if (row < 2)
|
|
19
|
+
return col < 3 ? "fire" : "water";
|
|
20
|
+
if (row === 2) {
|
|
21
|
+
if (col === 2)
|
|
22
|
+
return "sol";
|
|
23
|
+
return col < 2 ? "earth" : "water";
|
|
24
|
+
}
|
|
25
|
+
if (row > 2)
|
|
26
|
+
return col < 2 ? "earth" : "air";
|
|
27
|
+
return "invalid-position";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The finished cross, row by row: each square's symbol by its id in
|
|
31
|
+
* magick-data, and `null` where the cross has no square.
|
|
32
|
+
*/
|
|
33
|
+
export const FYLFOT_CELLS = [
|
|
34
|
+
["fire", "sagittarius", "leo", null, "water"],
|
|
35
|
+
[null, null, "aries", null, "pisces"],
|
|
36
|
+
["taurus", "capricorn", "sol", "cancer", "scorpio"],
|
|
37
|
+
["virgo", null, "libra", null, null],
|
|
38
|
+
["earth", null, "aquarius", "gemini", "air"],
|
|
39
|
+
];
|
|
40
|
+
/** The tables the squares' symbols come from. */
|
|
41
|
+
const TABLES = { planet: planets, element: elements, zodiac };
|
|
42
|
+
/** The magick-data table a symbol of the cross is a row of. */
|
|
43
|
+
export function fylfotSymbolTable(id) {
|
|
44
|
+
if (id === "sol")
|
|
45
|
+
return "planet";
|
|
46
|
+
if (["earth", "air", "water", "fire"].includes(id))
|
|
47
|
+
return "element";
|
|
48
|
+
return "zodiac";
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The table's class, which scopes its stylesheet: a plain `<style>`, so the
|
|
52
|
+
* component needs no CSS tooling (it was Next's styled-jsx in the app).
|
|
53
|
+
*/
|
|
54
|
+
const CLASS = "magick-fylfot-cross";
|
|
55
|
+
/** The custom property `ink` sets on the table, which the borders read. */
|
|
56
|
+
const INK = "--magick-fylfot-cross-ink";
|
|
57
|
+
const STYLE = `
|
|
58
|
+
.${CLASS} {
|
|
59
|
+
margin: 20px auto;
|
|
60
|
+
border-collapse: collapse;
|
|
61
|
+
}
|
|
62
|
+
.${CLASS} td {
|
|
63
|
+
width: 1.5em;
|
|
64
|
+
font-size: 200%;
|
|
65
|
+
text-align: center;
|
|
66
|
+
vertical-align: middle;
|
|
67
|
+
}
|
|
68
|
+
.${CLASS} td:not(:empty) {
|
|
69
|
+
border: 1px solid var(${INK}, black);
|
|
70
|
+
}
|
|
71
|
+
`;
|
|
72
|
+
/** The fylfot cross of the signs and elements, as a table of squares. */
|
|
73
|
+
export function FylfotCross({ cells = FYLFOT_CELLS, onCellClick, showColors = true, ink, }) {
|
|
74
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { children: STYLE }), _jsx("table", { className: CLASS, style: ink === undefined ? undefined : { [INK]: ink }, children: _jsx("tbody", { children: cells.map((row, rowIndex) => (_jsx("tr", { children: row.map((id, colIndex) => {
|
|
75
|
+
const expected = FYLFOT_CELLS[rowIndex]?.[colIndex] ?? null;
|
|
76
|
+
const isCorrect = id === expected;
|
|
77
|
+
const onClick = onCellClick && id !== null && id !== "cursor"
|
|
78
|
+
? () => onCellClick({
|
|
79
|
+
id,
|
|
80
|
+
row: rowIndex,
|
|
81
|
+
column: colIndex,
|
|
82
|
+
expected,
|
|
83
|
+
})
|
|
84
|
+
: undefined;
|
|
85
|
+
let background = undefined;
|
|
86
|
+
let color = undefined;
|
|
87
|
+
const opacity = isCorrect ? 1 : 0.5;
|
|
88
|
+
if (showColors && id !== "sol") {
|
|
89
|
+
const element = elementFromPos(rowIndex, colIndex);
|
|
90
|
+
background = colorFromElement[element];
|
|
91
|
+
color = flashingColorFromColor[background];
|
|
92
|
+
}
|
|
93
|
+
const style = { background, color, opacity };
|
|
94
|
+
if (id === null)
|
|
95
|
+
return _jsx("td", {}, colIndex);
|
|
96
|
+
if (id === "")
|
|
97
|
+
return (_jsx("td", { onClick: onClick, style: {
|
|
98
|
+
...style,
|
|
99
|
+
cursor: onCellClick ? "pointer" : undefined,
|
|
100
|
+
}, children: "\u00A0" }, colIndex));
|
|
101
|
+
if (id === "cursor")
|
|
102
|
+
return (_jsx("td", { style: {
|
|
103
|
+
...style,
|
|
104
|
+
border: "2px solid " + (showColors ? color : "red"),
|
|
105
|
+
}, children: "\u00A0" }, colIndex));
|
|
106
|
+
const item = TABLES[fylfotSymbolTable(id)][id];
|
|
107
|
+
// console.log([id, type, item]);
|
|
108
|
+
return (_jsx("td", { onClick: onClick, style: {
|
|
109
|
+
...style,
|
|
110
|
+
cursor: onCellClick ? "pointer" : undefined,
|
|
111
|
+
// Inline, so no page font overrides it; a value with
|
|
112
|
+
// `!important` React drops on the client.
|
|
113
|
+
fontFamily: "monospace",
|
|
114
|
+
}, children:
|
|
115
|
+
// U+FE0E is Unicode Variation Selector VS15,
|
|
116
|
+
// i.e. prefer text character to emoji, so
|
|
117
|
+
// we can style it ourselves.
|
|
118
|
+
item.symbol + "\uFE0E" }, colIndex));
|
|
119
|
+
}) }, rowIndex))) }) })] }));
|
|
120
|
+
}
|
|
121
|
+
export default FylfotCross;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type TreeOfLifeProps } from "../kabbalah/TreeOfLife.tsx";
|
|
2
|
+
/**
|
|
3
|
+
* The Tree of Life as the map of the Golden Dawn's grades: each sphere
|
|
4
|
+
* labelled with its grade's number and name, with the grade's element,
|
|
5
|
+
* order and planet below. Like the Tree, it links nothing unless given
|
|
6
|
+
* `sephirahHref` or `pathHref` (a sphere's row names its grade as
|
|
7
|
+
* `gdGradeId`). Any of `TreeOfLife`'s props override these.
|
|
8
|
+
*/
|
|
9
|
+
export declare function GradeTree({ ...props }: TreeOfLifeProps): import("react").JSX.Element;
|
|
10
|
+
export default GradeTree;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { TreeOfLife } from "../kabbalah/TreeOfLife.js";
|
|
3
|
+
/*
|
|
4
|
+
* The Tree with each sephirah numbered and named by its grade.
|
|
5
|
+
*
|
|
6
|
+
* A Server Component, as every page that draws it is (/gd through Tiles,
|
|
7
|
+
* /gd/grades and each grade's page). Nothing here needs the client, and
|
|
8
|
+
* marked "use client" it carried the barrel the Tree reads into those
|
|
9
|
+
* routes' client chunks (plan 036, decision 10).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The Tree of Life as the map of the Golden Dawn's grades: each sphere
|
|
13
|
+
* labelled with its grade's number and name, with the grade's element,
|
|
14
|
+
* order and planet below. Like the Tree, it links nothing unless given
|
|
15
|
+
* `sephirahHref` or `pathHref` (a sphere's row names its grade as
|
|
16
|
+
* `gdGradeId`). Any of `TreeOfLife`'s props override these.
|
|
17
|
+
*/
|
|
18
|
+
export function GradeTree({ ...props }) {
|
|
19
|
+
return (_jsx(TreeOfLife, { field: "gdGrade.id", topText: "gdGrade.name", bottomText: "gdGrade.element.symbol,gdGrade.orderId,gdGrade.planet.symbol", ...props }));
|
|
20
|
+
}
|
|
21
|
+
export default GradeTree;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
/** The officers whose lamen `Lamen` draws; any other draws the same plain one. */
|
|
3
|
+
export declare const LAMEN_OFFICERS: ReadonlySet<string>;
|
|
4
|
+
/**
|
|
5
|
+
* A Golden Dawn officer's lamen: the collar's ring, the disc and the
|
|
6
|
+
* officer's glyph, in a −50…50 box. It defines no ids, so any number can
|
|
7
|
+
* share a page.
|
|
8
|
+
*/
|
|
9
|
+
export declare function Lamen({ officer, grade, width, height, ringStyle, discStyle, }: {
|
|
10
|
+
/**
|
|
11
|
+
* The officer, in camel case (`hierophant`, `pastHierophant`,
|
|
12
|
+
* `chiefAdept`; `LAMEN_OFFICERS` lists them). Any other draws a plain
|
|
13
|
+
* lamen, and an empty one the Hierophant's.
|
|
14
|
+
*/
|
|
15
|
+
officer: string;
|
|
16
|
+
/**
|
|
17
|
+
* The grade whose lamen to draw, for an officer who wears another in it:
|
|
18
|
+
* `portal` for the Portal's Hiereus and Hegemon. Otherwise the Outer
|
|
19
|
+
* Order's lamen.
|
|
20
|
+
*/
|
|
21
|
+
grade?: string;
|
|
22
|
+
/** The SVG's width; from the height when not given, as it is square. */
|
|
23
|
+
width?: number | string;
|
|
24
|
+
/** The SVG's height; from the width when not given, as it is square. */
|
|
25
|
+
height?: number | string;
|
|
26
|
+
/** Style for the collar's ring, the outer circle. */
|
|
27
|
+
ringStyle?: React.CSSProperties;
|
|
28
|
+
/** Style for the disc, the inner circle. */
|
|
29
|
+
discStyle?: React.CSSProperties;
|
|
30
|
+
}): React.JSX.Element;
|
|
31
|
+
export default Lamen;
|
package/lib/gd/Lamen.js
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { flipped } from "./hall/art/geometry.js";
|
|
3
|
+
import { CupOnOctagram, PortalHegemon, PortalHiereus, RoseCross, TriangleInPentagram, } from "./lamenGlyphs.js";
|
|
4
|
+
/**
|
|
5
|
+
* Lamens bearing the Calvary cross, by officer. The Hierophant is not a
|
|
6
|
+
* Temple Chief but has the Imperator's cross. Looked up in a `Map`, so an
|
|
7
|
+
* officer name such as "constructor" is simply not found.
|
|
8
|
+
*
|
|
9
|
+
* The ring shows the officer's collar, by Gadi's own convention, so the
|
|
10
|
+
* roles stay distinguishable even as 20 px ritual role icons: Imperator
|
|
11
|
+
* red, Praemonstrator blue, Cancellarius yellow on a purple disc,
|
|
12
|
+
* Hierophant red and white stripes, Past Hierophant white, every lamen
|
|
13
|
+
* the same size. The sources differ: Regardie (*The Golden Dawn*) hangs
|
|
14
|
+
* the Hierophant's lamen from a white collar, the Imperator's scarlet,
|
|
15
|
+
* the Praemonstrator's blue and the Cancellarius' purple, and gives the
|
|
16
|
+
* Past Hierophant only "a Jewel of that Lamen"; the Ciceros paint the
|
|
17
|
+
* ring in the cross's colour and draw the Past Hierophant's lamen
|
|
18
|
+
* smaller; red and white stripes are the Hierophant's nemyss in Zalewski
|
|
19
|
+
* and in the Ciceros.
|
|
20
|
+
*
|
|
21
|
+
* Sources, by title, edition and page (plan 061, decision 9):
|
|
22
|
+
* - Israel Regardie, *The Golden Dawn*, vol. 3 (Aries Press, 1939), Z.1:
|
|
23
|
+
* pp. 82–84, the Chiefs' lamens and collars and "a Jewel of that Lamen"
|
|
24
|
+
* for a Past Hierophant; pp. 88–90, the Hierophant's lamen on a white
|
|
25
|
+
* collar.
|
|
26
|
+
* - Pat Zalewski, *Secret Teachings of the Golden Dawn, Book 1: The
|
|
27
|
+
* Neophyte Ritual 0=0* (Llewellyn, 1991): p. 76, the Hierophant's
|
|
28
|
+
* scarlet-and-white-striped nemyss; p. 78 (Fig. 26), the lamen drawn
|
|
29
|
+
* with an outer ring; p. 87, Whare Ra's white-field variant.
|
|
30
|
+
* - Chic and Sandra Tabatha Cicero, *Secrets of a Golden Dawn Temple*
|
|
31
|
+
* (Thoth, 2004): pp. 80–81, the collars and the Past Hierophant's
|
|
32
|
+
* smaller lamen; pp. 96–97, the ring in the charge colour.
|
|
33
|
+
*/
|
|
34
|
+
const CROSS_LAMENS = new Map([
|
|
35
|
+
["imperator", { ring: "red", disc: "green" }],
|
|
36
|
+
["praemonstrator", { ring: "#48f", disc: "orange" }],
|
|
37
|
+
["cancellarius", { ring: "yellow", disc: "#b5b" }],
|
|
38
|
+
["hierophant", { ring: "stripes", disc: "green", cross: "red" }],
|
|
39
|
+
["pastHierophant", { ring: "white", disc: "green", cross: "red" }],
|
|
40
|
+
]);
|
|
41
|
+
/**
|
|
42
|
+
* The adepts' lamens, from the Portal's rubric (Regardie, *The Golden
|
|
43
|
+
* Dawn*, vol. 2, Aries Press, 1938, p. 156; archive.org
|
|
44
|
+
* `IsraelRegardie-TheGoldenDawn-Vol2-1938`, leaf n149): the Chief Adept's
|
|
45
|
+
* Rose-Cross on a yellow collar, the Second Adept's red triangle in a
|
|
46
|
+
* green pentagram on a white one, the Third Adept's blue cup on an orange
|
|
47
|
+
* octagram on a blue one. The ring shows the collar, as for the Chiefs;
|
|
48
|
+
* the Third Adept's blue is the Praemonstrator's. These are the Portal's
|
|
49
|
+
* lamens only: in a 5=6 hall, under the same role names, the Adepts wear
|
|
50
|
+
* the Rose-Cross, the Second's and Third's by inference
|
|
51
|
+
* (`lamenGrades.ts`).
|
|
52
|
+
*/
|
|
53
|
+
const GLYPH_LAMENS = new Map([
|
|
54
|
+
["chiefAdept", { ring: "yellow", Glyph: RoseCross }],
|
|
55
|
+
["secondAdept", { ring: "white", Glyph: TriangleInPentagram }],
|
|
56
|
+
["thirdAdept", { ring: "#48f", Glyph: CupOnOctagram }],
|
|
57
|
+
]);
|
|
58
|
+
/**
|
|
59
|
+
* The lamens an officer wears in a particular grade instead of the Outer
|
|
60
|
+
* Order's, by `grade:officer` (`lamenGrades.ts`), from the Portal's
|
|
61
|
+
* rubric (Regardie 1938, vol. 2, p.156, leaf n149). The Hiereus wears a
|
|
62
|
+
* white hexagram on the four colours of Malkuth. His ring is red: the
|
|
63
|
+
* p.156 list gives him two collars and no cloak ("Black Collar", then
|
|
64
|
+
* "Red Shoes and Collar"), and we read "Black Collar" as a misprint for
|
|
65
|
+
* "Black Cloak", which keeps the Outer Order's scarlet collar (Z.1,
|
|
66
|
+
* vol. 3, pp.92–93, leaves n84–85). Should Gadi choose black instead,
|
|
67
|
+
* the ring becomes a dark grey (about `#333`) with the usual outline.
|
|
68
|
+
* The Hegemon wears a red and blue hexagram on a white ground, on a
|
|
69
|
+
* yellow collar.
|
|
70
|
+
*/
|
|
71
|
+
const GRADE_LAMENS = new Map([
|
|
72
|
+
["portal:hiereus", { ring: "red", Glyph: PortalHiereus }],
|
|
73
|
+
["portal:hegemon", { ring: "yellow", disc: "white", Glyph: PortalHegemon }],
|
|
74
|
+
]);
|
|
75
|
+
/**
|
|
76
|
+
* The Hegemon's Calvary cross is black on a white disc: "the black
|
|
77
|
+
* Calvary Cross" on a black collar (Regardie, *The Golden Dawn*, vol. 3,
|
|
78
|
+
* Aries Press, 1939, Z.1, p. 95; archive.org
|
|
79
|
+
* `IsraelRegardie-TheGoldenDawn-Vol3-1939`, leaf n87), and Mathers'
|
|
80
|
+
* manuscript sheet of the lamens has a black cross on white with a black
|
|
81
|
+
* border. The other floor officers' glyphs are white on black. His ring
|
|
82
|
+
* stays white, as every floor officer's, rather than his black collar's,
|
|
83
|
+
* which would vanish into the outline: the rings are our convention.
|
|
84
|
+
*/
|
|
85
|
+
const HEGEMON_DISC = "white";
|
|
86
|
+
const HEGEMON_CROSS = "#000";
|
|
87
|
+
/** The officers whose lamen `Lamen` draws; any other draws the same plain one. */
|
|
88
|
+
export const LAMEN_OFFICERS = new Set([
|
|
89
|
+
...CROSS_LAMENS.keys(),
|
|
90
|
+
...GLYPH_LAMENS.keys(),
|
|
91
|
+
"hegemon",
|
|
92
|
+
"hiereus",
|
|
93
|
+
"stolistes",
|
|
94
|
+
"dadouchos",
|
|
95
|
+
"keryx",
|
|
96
|
+
"sentinel",
|
|
97
|
+
]);
|
|
98
|
+
/** The ring's outer radius, inside the −50…50 viewBox; the disc's is 42. */
|
|
99
|
+
const RING_RADIUS = 49;
|
|
100
|
+
/** Height of each of the Hierophant's ring stripes, in lamen units. */
|
|
101
|
+
const STRIPE = 8;
|
|
102
|
+
/**
|
|
103
|
+
* The part of the ring's disc between heights `a` and `b`, as a path: the
|
|
104
|
+
* two arcs of the circle and the chords joining them.
|
|
105
|
+
*/
|
|
106
|
+
function discSlab(a, b, r = RING_RADIUS) {
|
|
107
|
+
const top = Math.max(a, -r);
|
|
108
|
+
const bottom = Math.min(b, r);
|
|
109
|
+
const half = (y) => +Math.sqrt(r * r - y * y).toFixed(3);
|
|
110
|
+
const [xt, xb] = [half(top), half(bottom)];
|
|
111
|
+
return `M${xt} ${top}A${r} ${r} 0 0 1 ${xb} ${bottom}H${-xb}A${r} ${r} 0 0 1 ${-xt} ${top}Z`;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The white stripes of the Hierophant's ring, drawn over its red fill: a
|
|
115
|
+
* red stripe is centred on the horizontal diameter, so the ring is
|
|
116
|
+
* symmetric top to bottom (red, then white, every 8 units outward). Plain
|
|
117
|
+
* geometry under the disc rather than a `<pattern>`, so the lamen defines
|
|
118
|
+
* no ids and any number of them can share a page, inside a hall's `<defs>`
|
|
119
|
+
* or in renderers without hooks.
|
|
120
|
+
*/
|
|
121
|
+
const RING_STRIPES = [1, 3, 5]
|
|
122
|
+
.flatMap((n) => [
|
|
123
|
+
discSlab((n - 0.5) * STRIPE, (n + 0.5) * STRIPE),
|
|
124
|
+
discSlab(-(n + 0.5) * STRIPE, -(n - 0.5) * STRIPE),
|
|
125
|
+
])
|
|
126
|
+
.join("");
|
|
127
|
+
const TipharethCalvaryCross = ({ style, scale = 7.5, }) => (_jsx("path", { d: "M -1.1 -4.8 v.708a3.045 3.045 0 0 0-1.842 1.806h-.64v2.02h.601a3.045 3.045 0 0 0 1.881 1.91v3.134h2.02v-3.14a3.045 3.045 0 0 0 1.867-1.904h.615v-2.02h-.653a3.045 3.045 0 0 0-1.829-1.8v-.714zm2.02 1.256a2.534 2.534 0 0 1 1.285 1.258h-1.285zm-2.02 0v1.258h-1.292a2.534 2.534 0 0 1 1.292-1.257zm-1.334 3.278h1.334v1.361a2.534 2.534 0 0 1-1.334-1.36zm3.354 0h1.329a2.534 2.534 0 0 1-1.329 1.362z", style: {
|
|
128
|
+
fill: "red",
|
|
129
|
+
stroke: "black",
|
|
130
|
+
strokeWidth: 1 / scale - 0.05,
|
|
131
|
+
...style,
|
|
132
|
+
}, transform: "scale(" + scale + ")" }));
|
|
133
|
+
/**
|
|
134
|
+
* The caduceus of the Keryx's lamen, drawn from geometry in lamen units
|
|
135
|
+
* (plan 061, stage H, part 2, follow-ups: Gadi chose wings V1 with two
|
|
136
|
+
* turns of the serpents on 26 October 2026). A pointed staff topped by a
|
|
137
|
+
* ringed ball, two wings, and two serpents wound round the staff as a
|
|
138
|
+
* double helix seen a little from above, their heads turned outward
|
|
139
|
+
* below the wings.
|
|
140
|
+
*
|
|
141
|
+
* Each serpent winds `x = A(u)·sin θ` from the tail (u = 0) to the neck
|
|
142
|
+
* (u = 1), with a small tilt `TILT · dy/dθ · cos θ` added to y that
|
|
143
|
+
* rounds the loops. The reach `A` falls towards the tail, the turning
|
|
144
|
+
* rate rises there (the coils tighten), and the body thins arc by arc.
|
|
145
|
+
* The serpent is cut into half-turn arcs where it turns at a side: the
|
|
146
|
+
* arcs behind (cos θ < 0) are drawn under the staff, those in front over
|
|
147
|
+
* it on a band of the disc's black, so the depth settles every crossing.
|
|
148
|
+
* Each arc is a few Hermite cubics through eighth-turn knots, rounded to
|
|
149
|
+
* one decimal: no ids, no gradients.
|
|
150
|
+
*/
|
|
151
|
+
const TURNS = 2;
|
|
152
|
+
/** The body's width at the neck, and the share of it left at the tail. */
|
|
153
|
+
const BODY = 5;
|
|
154
|
+
const THIN = 0.6;
|
|
155
|
+
/** The black edge either side of a front arc and of the staff. */
|
|
156
|
+
const EDGE = 1.25;
|
|
157
|
+
/** The widest swing, at the neck, and the share of it left at the tail. */
|
|
158
|
+
const REACH = 12;
|
|
159
|
+
const TAPER = 0.4;
|
|
160
|
+
/** How much faster the coils turn at the tail than at the neck (+90%). */
|
|
161
|
+
const TIGHTEN = 0.9;
|
|
162
|
+
const TAIL = 35;
|
|
163
|
+
const NECK = -10;
|
|
164
|
+
const TILT = 0.3;
|
|
165
|
+
/** Knots per serpent: one every eighth of a turn. */
|
|
166
|
+
const KNOTS = TURNS * 8;
|
|
167
|
+
const r1 = (value) => Math.round(value * 10) / 10 + 0;
|
|
168
|
+
const xy = ([x, y]) => `${r1(x)},${r1(y)}`;
|
|
169
|
+
/**
|
|
170
|
+
* How far along the serpent (u, tail 0 to neck 1) it has made `share` of
|
|
171
|
+
* its turns, the turning rate falling linearly from 1 + TIGHTEN at the
|
|
172
|
+
* tail to 1 at the neck.
|
|
173
|
+
*/
|
|
174
|
+
const along = (share) => (1 +
|
|
175
|
+
TIGHTEN -
|
|
176
|
+
Math.sqrt((1 + TIGHTEN) ** 2 - 2 * TIGHTEN * share * (1 + TIGHTEN / 2))) /
|
|
177
|
+
TIGHTEN;
|
|
178
|
+
/** The angle at `share` of the turns: π/2 at the neck (and the tail). */
|
|
179
|
+
const angle = (side, share) => Math.PI / 2 + 2 * Math.PI * TURNS * (share - 1) + (side < 0 ? Math.PI : 0);
|
|
180
|
+
/** A serpent's centre line at `share` of its turns. */
|
|
181
|
+
function coil(side, share) {
|
|
182
|
+
const u = along(share);
|
|
183
|
+
const theta = angle(side, share);
|
|
184
|
+
// dy/dθ: how far the coil falls per radian here.
|
|
185
|
+
const pitch = ((NECK - TAIL) * (1 + TIGHTEN / 2)) /
|
|
186
|
+
((1 + TIGHTEN - TIGHTEN * u) * 2 * Math.PI * TURNS);
|
|
187
|
+
return [
|
|
188
|
+
REACH * (TAPER + (1 - TAPER) * u) * Math.sin(theta),
|
|
189
|
+
TAIL + (NECK - TAIL) * u + TILT * pitch * Math.cos(theta),
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
/** The centre line from share `a` to `b` in `pieces` Hermite cubics. */
|
|
193
|
+
function coilPath(side, a, b, pieces) {
|
|
194
|
+
const tangent = (share) => {
|
|
195
|
+
const h = 1e-4;
|
|
196
|
+
const [p, q] = [coil(side, share - h), coil(side, share + h)];
|
|
197
|
+
return [(q[0] - p[0]) / (2 * h), (q[1] - p[1]) / (2 * h)];
|
|
198
|
+
};
|
|
199
|
+
let d = `M${xy(coil(side, a))}`;
|
|
200
|
+
for (let i = 0; i < pieces; i++) {
|
|
201
|
+
const [s0, s1] = [
|
|
202
|
+
a + ((b - a) * i) / pieces,
|
|
203
|
+
a + ((b - a) * (i + 1)) / pieces,
|
|
204
|
+
];
|
|
205
|
+
const k = (s1 - s0) / 3;
|
|
206
|
+
const [p0, p1, t0, t1] = [
|
|
207
|
+
coil(side, s0),
|
|
208
|
+
coil(side, s1),
|
|
209
|
+
tangent(s0),
|
|
210
|
+
tangent(s1),
|
|
211
|
+
];
|
|
212
|
+
d += `C${xy([p0[0] + t0[0] * k, p0[1] + t0[1] * k])} ${xy([p1[0] - t1[0] * k, p1[1] - t1[1] * k])} ${xy(p1)}`;
|
|
213
|
+
}
|
|
214
|
+
return d;
|
|
215
|
+
}
|
|
216
|
+
const BEHIND = [];
|
|
217
|
+
const IN_FRONT = [];
|
|
218
|
+
/** Each head: its centre, and the angle it leans out. */
|
|
219
|
+
const HEADS = [];
|
|
220
|
+
for (const side of [1, -1]) {
|
|
221
|
+
// Half-turn arcs, from one side turn to the next: the tail is at a side
|
|
222
|
+
// too, as TURNS is whole.
|
|
223
|
+
for (let i = 0; i < KNOTS; i += 4) {
|
|
224
|
+
const [a, b] = [i / KNOTS, (i + 4) / KNOTS];
|
|
225
|
+
const width = r1(BODY * (THIN + (1 - THIN) * along((a + b) / 2)));
|
|
226
|
+
const d = coilPath(side, a, b, 4);
|
|
227
|
+
if (Math.cos(angle(side, (a + b) / 2)) < 0)
|
|
228
|
+
BEHIND.push({ d, width });
|
|
229
|
+
else {
|
|
230
|
+
// The black band only over the arc's middle, where it crosses the
|
|
231
|
+
// staff and the other serpent, clear of the turns at the sides.
|
|
232
|
+
const trim = (b - a) * 0.17;
|
|
233
|
+
IN_FRONT.push({
|
|
234
|
+
d: coilPath(side, a + trim, b - trim, 3),
|
|
235
|
+
width: width + 2 * EDGE,
|
|
236
|
+
band: true,
|
|
237
|
+
}, { d, width });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// The neck rises and leans outward to the head.
|
|
241
|
+
const [x, y] = coil(side, 1);
|
|
242
|
+
const [hx, hy] = [x + side * 2.6, y - 3];
|
|
243
|
+
IN_FRONT.push({
|
|
244
|
+
d: `M${xy([x, y])}Q${xy([x + side * 0.3, y - 2.2])} ${xy([hx, hy])}`,
|
|
245
|
+
width: BODY,
|
|
246
|
+
});
|
|
247
|
+
HEADS.push({ cx: r1(hx + side * 1.2), cy: r1(hy - 1), lean: -side * 35 });
|
|
248
|
+
}
|
|
249
|
+
/** The staff, pointed at the foot, its top hidden by the ball. */
|
|
250
|
+
const STAFF = "M-1.7,-26H1.7V36L0,38.4L-1.7,36Z";
|
|
251
|
+
/**
|
|
252
|
+
* One wing (the right), in lamen units; flipped for the left. Design V1
|
|
253
|
+
* ("Arch"): the top edge leaves the ball's side, dips under it (the notch
|
|
254
|
+
* the ball's ring closes), rises to a crest beside the ball and falls to
|
|
255
|
+
* a far, low tip; the underside is flat, cut into four round feathers.
|
|
256
|
+
*/
|
|
257
|
+
const WING = "M0,-24.5Q3.8,-20.4 6,-21C9.5,-22.5 9,-30.6 14,-31Q25.8,-25.2 35.5,-16.5C35.5,-14.4 30.9,-13.8 29.3,-16.6C29.3,-13.6 24.1,-13 22.5,-16.2C22.5,-13.2 16.7,-12.6 15.1,-15.8C15.1,-12.8 8.6,-12.2 7,-15.4Q2.4,-14.9 0,-19Z";
|
|
258
|
+
const WINGS = WING + flipped(WING);
|
|
259
|
+
/** The Keryx's caduceus, white on the black disc, in lamen units. */
|
|
260
|
+
function Caduceus() {
|
|
261
|
+
const strokes = (list) => list.map(({ d, width, band }) => band ? (_jsx("path", { d: d, stroke: "black", strokeWidth: width, strokeLinecap: "butt" }, `b${d}`)) : (_jsx("path", { d: d, strokeWidth: width }, d)));
|
|
262
|
+
return (_jsxs("g", { fill: "white", children: [_jsxs("g", { fill: "none", stroke: "white", strokeLinecap: "round", children: [strokes(BEHIND), _jsx("path", { d: STAFF, fill: "white", stroke: "black", strokeWidth: 2 * EDGE, paintOrder: "stroke" }), strokes(IN_FRONT)] }), _jsx("path", { d: WINGS }), _jsx("g", { stroke: "black", strokeWidth: 1.2, children: HEADS.map(({ cx, cy, lean }) => (_jsx("ellipse", { cx: cx, cy: cy, rx: r1(BODY * 0.9), ry: r1(BODY * 0.6), transform: `rotate(${lean} ${cx} ${cy})` }, lean))) }), _jsx("circle", { cy: -27, r: 4.8, stroke: "black", strokeWidth: 1.6 })] }));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* The Sentinel's Eye of Horus (the wedjat), drawn from a few strokes after
|
|
266
|
+
* its ancient form (plan 061, stage H): the brow, the eye with its pupil,
|
|
267
|
+
* the line from the outer corner, the drop and the spiral. White on the
|
|
268
|
+
* black disc.
|
|
269
|
+
*/
|
|
270
|
+
function EyeOfHorus() {
|
|
271
|
+
return (_jsxs("g", { transform: "translate(-2 2)", fill: "white", stroke: "white", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M-30,-19C-16,-28 12,-29 33,-22L33,-16C12,-23 -16,-22 -30,-14Z", stroke: "none" }), _jsx("path", { d: "M-30,-3C-18,-15 10,-16 26,-5C12,3 -16,5 -30,-3Z", fill: "none", strokeWidth: 4.2 }), _jsx("path", { d: "M26,-5H38", strokeWidth: 4.6 }), _jsx("circle", { cx: -3, cy: -6.5, r: 7.2, stroke: "none" }), _jsx("path", { d: "M-11,1.5L-14,1.5L-13,28L-11.6,30Z", stroke: "none" }), _jsx("path", { d: "M2,2C5,15 13,22 22,22C30,22 32,13 26,11C21.5,9.5 19,14 22.5,16", fill: "none", strokeWidth: 4 })] }));
|
|
272
|
+
}
|
|
273
|
+
// Every lamen is drawn for magick.ly: the Keryx's caduceus and the
|
|
274
|
+
// Sentinel's Eye of Horus from geometry since stage H of plan 061 (they
|
|
275
|
+
// were an SVG Repo icon and a game-icons.net path before), the adepts'
|
|
276
|
+
// since its second part.
|
|
277
|
+
/**
|
|
278
|
+
* A Golden Dawn officer's lamen: the collar's ring, the disc and the
|
|
279
|
+
* officer's glyph, in a −50…50 box. It defines no ids, so any number can
|
|
280
|
+
* share a page.
|
|
281
|
+
*/
|
|
282
|
+
export function Lamen({ officer, grade, width, height, ringStyle, discStyle, }) {
|
|
283
|
+
if (!officer)
|
|
284
|
+
officer = "hierophant";
|
|
285
|
+
const gradeLamen = grade === undefined ? undefined : GRADE_LAMENS.get(`${grade}:${officer}`);
|
|
286
|
+
// A grade's own lamen replaces the officer's white-on-black glyph.
|
|
287
|
+
const glyph = gradeLamen ? "" : officer;
|
|
288
|
+
const crossLamen = CROSS_LAMENS.get(officer);
|
|
289
|
+
const glyphLamen = gradeLamen ?? GLYPH_LAMENS.get(officer);
|
|
290
|
+
const _ringStyle = {
|
|
291
|
+
color: "#000",
|
|
292
|
+
overflow: "visible",
|
|
293
|
+
fill: crossLamen?.ring === "stripes"
|
|
294
|
+
? "red"
|
|
295
|
+
: (crossLamen?.ring ?? glyphLamen?.ring ?? "white"),
|
|
296
|
+
stroke: "#000",
|
|
297
|
+
strokeWidth: 1,
|
|
298
|
+
strokeDasharray: "none",
|
|
299
|
+
paintOrder: "stroke fill markers",
|
|
300
|
+
stopColor: "#000",
|
|
301
|
+
...ringStyle,
|
|
302
|
+
};
|
|
303
|
+
const _discStyle = {
|
|
304
|
+
color: "#000",
|
|
305
|
+
overflow: "visible",
|
|
306
|
+
fill: crossLamen?.disc ??
|
|
307
|
+
glyphLamen?.disc ??
|
|
308
|
+
(glyph === "hegemon" ? HEGEMON_DISC : "#000"),
|
|
309
|
+
stroke: "#000",
|
|
310
|
+
strokeWidth: 1,
|
|
311
|
+
paintOrder: "stroke fill markers",
|
|
312
|
+
stopColor: "#000",
|
|
313
|
+
...discStyle,
|
|
314
|
+
};
|
|
315
|
+
return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", xmlSpace: "preserve", width: width, height: height, viewBox: "-50 -50 100 100", children: [_jsx("circle", { cx: 0, cy: 0, r: RING_RADIUS, style: _ringStyle }), crossLamen?.ring === "stripes" && _jsx("path", { d: RING_STRIPES, fill: "white" }), _jsx("circle", { cx: 0, cy: 0, r: 42, style: _discStyle }), crossLamen && (_jsx(TipharethCalvaryCross, { style: { fill: crossLamen.cross ?? crossLamen.ring } })), glyph === "hegemon" && (_jsx("path", { d: "M 0 0 h2.482v2.02h-2.482v5.043h-2.02v-5.043h-2.482v-2.02h2.481v-2.515h2.02z", style: { fill: HEGEMON_CROSS }, transform: "scale(7.2) translate(1,-2.2)" })), glyph === "hiereus" && (_jsx("path", { d: "m114.746 96.37-4.93 8.54h9.86zm0 2.13 3.087 5.346h-6.174z", style: { fill: "white" }, transform: "scale(6) translate(-114.7,-101.5)" })), glyph === "stolistes" && (_jsx("path", { d: "M79.292 93.798H69.273l5.002-6.66zm-2.397-8.903a2.62 2.62 0 0 1-2.62 2.62 2.62 2.62 0 0 1-2.622-2.62 2.62 2.62 0 0 1 2.621-2.62 2.62 2.62 0 0 1 2.621 2.62zm-9.152-10.753H80.81c-.448 4.994-3.182 7.714-6.523 8.346-3.279-.596-6.12-3.083-6.544-8.346z", style: { fill: "white" }, transform: "scale(3.3) translate(-74.2,-83.5)" })), glyph === "dadouchos" && (_jsx("path", { d: "M30.12 92.248V88.65h3.598v3.598zm0-3.587v-3.597h3.598v3.597zm0-3.587v-3.597h3.598v3.597zm3.587 0v-3.597h3.597v3.597zm3.587 0v-3.597h3.597v3.597zm10.767 7.174h-3.597V88.65h3.597zm-3.587 0h-3.597V88.65h3.597zm-3.587 0H37.29V88.65h3.597zm0-3.587H37.29v-3.597h3.597zm0-3.587H37.29v-3.597h3.597zM48.061 74.3v3.597h-3.597v-3.597zm0 3.587v3.597h-3.597v-3.597zm0 3.587v3.597h-3.597v-3.597zm-3.587 0v3.597h-3.597v-3.597zm-3.587 0v3.597H37.29v-3.597Zm-10.766-7.182h3.597v3.597H30.12Zm3.586 0h3.598v3.597h-3.598zm3.587 0h3.597v3.597h-3.597zm0 3.587h3.597v3.597h-3.597zm0 3.587h3.597v3.597h-3.597z", style: { fill: "white" }, transform: "scale(2.9) translate(-39,-83.5)" })), glyph === "keryx" && _jsx(Caduceus, {}), glyph === "sentinel" && _jsx(EyeOfHorus, {}), glyphLamen && _jsx(glyphLamen.Glyph, {})] }));
|
|
316
|
+
}
|
|
317
|
+
export default Lamen;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type RoseVersionId } from "./roseSigilGeometry.ts";
|
|
3
|
+
export interface RoseSigilProps {
|
|
4
|
+
/**
|
|
5
|
+
* The text to draw. Final forms are drawn as their base letters, and
|
|
6
|
+
* anything not one of the 22 letters (spaces, points, Latin) is left out.
|
|
7
|
+
*/
|
|
8
|
+
text: string;
|
|
9
|
+
/** Draws the rose's three rings of letters behind the sigil. */
|
|
10
|
+
showRose?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Which rose the sigil is traced on (`ROSE_VERSIONS`): the Golden
|
|
13
|
+
* Dawn's (`gd`) when not given or not a version, or Regardie's of 1939
|
|
14
|
+
* (`regardie1939`), which exchanges Kaph and Tau. `ROSE_VERSION_NOTES`
|
|
15
|
+
* says where each comes from.
|
|
16
|
+
*/
|
|
17
|
+
version?: RoseVersionId;
|
|
18
|
+
/** Draws the connecting path on, once the layout is optimised. */
|
|
19
|
+
animate?: boolean;
|
|
20
|
+
/** The `<svg>`, for exporting the drawing. */
|
|
21
|
+
ref?: React.Ref<SVGSVGElement>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The rose-cross sigil of a Hebrew text, drawn through the letters' places
|
|
25
|
+
* on the rose. It renders the letter centres first, on the server too, then
|
|
26
|
+
* spreads repeated and aligned letters with the optimiser once in the
|
|
27
|
+
* browser, and draws the path on. A client component: the server-safe
|
|
28
|
+
* drawing is `RoseSigilImage`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function RoseSigil({ text, showRose, version, animate, ref, }: RoseSigilProps): React.JSX.Element;
|
|
31
|
+
export default RoseSigil;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { RoseSigilImage } from "./RoseSigilImage.js";
|
|
5
|
+
import { sigilPoints, } from "./roseSigilGeometry.js";
|
|
6
|
+
import { optimizeSigilPoints } from "./roseSigilOptimizer.js";
|
|
7
|
+
/**
|
|
8
|
+
* The rose-cross sigil of a Hebrew text, drawn through the letters' places
|
|
9
|
+
* on the rose. It renders the letter centres first, on the server too, then
|
|
10
|
+
* spreads repeated and aligned letters with the optimiser once in the
|
|
11
|
+
* browser, and draws the path on. A client component: the server-safe
|
|
12
|
+
* drawing is `RoseSigilImage`.
|
|
13
|
+
*/
|
|
14
|
+
export function RoseSigil({ text, showRose = true, version, animate = true, ref, }) {
|
|
15
|
+
const pathRef = React.useRef(null);
|
|
16
|
+
// useId yields ":r1:"-style ids; CSS identifiers need the colons removed.
|
|
17
|
+
const animation = `rose-sigil-draw-${React.useId().replace(/[^\w-]/g, "")}`;
|
|
18
|
+
const points = React.useMemo(() => sigilPoints(text, version), [text, version]);
|
|
19
|
+
const [optimized, setOptimized] = React.useState(null);
|
|
20
|
+
React.useEffect(() => {
|
|
21
|
+
if (!points.length)
|
|
22
|
+
return;
|
|
23
|
+
let cancelled = false;
|
|
24
|
+
optimizeSigilPoints(points).then((result) => {
|
|
25
|
+
if (!cancelled)
|
|
26
|
+
setOptimized(result);
|
|
27
|
+
},
|
|
28
|
+
// Without the optimiser (its WASM failed to load) the sigil keeps
|
|
29
|
+
// the letter centres it was first drawn with.
|
|
30
|
+
(error) => console.error(error));
|
|
31
|
+
return () => {
|
|
32
|
+
cancelled = true;
|
|
33
|
+
};
|
|
34
|
+
}, [points]);
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
if (pathRef.current && optimized) {
|
|
37
|
+
const length = pathRef.current.getTotalLength();
|
|
38
|
+
pathRef.current.style.strokeDasharray = animate ? length.toString() : "";
|
|
39
|
+
pathRef.current.style.strokeDashoffset = animate ? length.toString() : "";
|
|
40
|
+
pathRef.current.classList.remove(animation);
|
|
41
|
+
// @ts-expect-error: trick to trigger reflow
|
|
42
|
+
void pathRef.current.offsetWidth;
|
|
43
|
+
if (animate)
|
|
44
|
+
pathRef.current.classList.add(animation);
|
|
45
|
+
}
|
|
46
|
+
}, [animate, animation, optimized]);
|
|
47
|
+
return (_jsx(RoseSigilImage, { text: text, showRose: showRose, version: version, debug: false, points: optimized || points, animation: animate ? animation : undefined, ref: ref, pathRef: pathRef }));
|
|
48
|
+
}
|
|
49
|
+
export default RoseSigil;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type RoseVersionId, type SigilPoint } from "./roseSigilInternals.ts";
|
|
3
|
+
export interface RoseSigilImageProps {
|
|
4
|
+
/**
|
|
5
|
+
* The text to draw. Final forms are drawn as their base letters, and
|
|
6
|
+
* anything not one of the 22 letters (spaces, points, Latin) is left out.
|
|
7
|
+
*/
|
|
8
|
+
text: string;
|
|
9
|
+
/** Draws the rose's three rings of letters behind the sigil (default true). */
|
|
10
|
+
showRose?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Which rose (`ROSE_VERSIONS`): the Golden Dawn's (`gd`) when not given
|
|
13
|
+
* or not a version, or Regardie's of 1939 (`regardie1939`), which
|
|
14
|
+
* exchanges Kaph and Tau. Give the `points` of the same version.
|
|
15
|
+
*/
|
|
16
|
+
version?: RoseVersionId;
|
|
17
|
+
/** Draws each letter's circle and the unoptimised path too (default false). */
|
|
18
|
+
debug?: boolean;
|
|
19
|
+
/** Letter centres to draw through; the optimised layout when available. */
|
|
20
|
+
points: SigilPoint[];
|
|
21
|
+
/**
|
|
22
|
+
* Draw-on animation class for the connecting path, unique per instance
|
|
23
|
+
* because a `<style>` inside inline SVG is document-wide; server renders
|
|
24
|
+
* never animate.
|
|
25
|
+
*/
|
|
26
|
+
animation?: string;
|
|
27
|
+
/** The `<svg>`, for exporting the drawing. */
|
|
28
|
+
ref?: React.Ref<SVGSVGElement>;
|
|
29
|
+
/** The connecting path, which `RoseSigil` animates. */
|
|
30
|
+
pathRef?: React.Ref<SVGPathElement>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The sigil's artwork with no hooks, so that a server-side renderer can
|
|
34
|
+
* draw it with React's server build; `RoseSigil` adds the optimiser and
|
|
35
|
+
* the animation around it.
|
|
36
|
+
*/
|
|
37
|
+
export declare function RoseSigilImage({ text, showRose, version, debug, points, animation, ref, pathRef, }: RoseSigilImageProps): React.JSX.Element;
|
|
38
|
+
export default RoseSigilImage;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { svgCoordinate } from "../svgCoordinate.js";
|
|
4
|
+
import { letterPoint, pathFromPoints, roseLetters, roseRings, sigilPoints, } from "./roseSigilInternals.js";
|
|
5
|
+
const roseStrokeColor = "rgba(0,0,0,.4)";
|
|
6
|
+
/**
|
|
7
|
+
* The sigil's artwork with no hooks, so that a server-side renderer can
|
|
8
|
+
* draw it with React's server build; `RoseSigil` adds the optimiser and
|
|
9
|
+
* the animation around it.
|
|
10
|
+
*/
|
|
11
|
+
export function RoseSigilImage({ text, showRose = true, version, debug = false, points, animation, ref, pathRef, }) {
|
|
12
|
+
const sigilTokens = roseLetters(text);
|
|
13
|
+
return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", version: "1.1", viewBox: "-50 -50 100 100", ref: ref, children: [animation && (_jsx("style", { children: `.${animation} { animation: ${animation} ${sigilTokens.length / 4}s linear 0s forwards 1; }
|
|
14
|
+
@keyframes ${animation} { to { stroke-dashoffset: 0; } }` })), showRose && (_jsxs(_Fragment, { children: [" ", _jsx("circle", { cx: 0, cy: 0, r: 10, stroke: roseStrokeColor, strokeWidth: 0.5, fill: "none" }), roseRings(version).map((row, i) => (_jsxs(React.Fragment, { children: [_jsx("circle", { cx: 0, cy: 0, r: 10 * (i + 2), stroke: roseStrokeColor, strokeWidth: 0.5, fill: "none" }), row.map((letter) => {
|
|
15
|
+
// Labels sit on the letter centres the path is drawn through.
|
|
16
|
+
const center = letterPoint(letter, version);
|
|
17
|
+
const x = svgCoordinate(center.x);
|
|
18
|
+
const y = svgCoordinate(center.y);
|
|
19
|
+
return (_jsxs(React.Fragment, { children: [debug && (_jsx("circle", { cx: x, cy: y, r: 5, stroke: roseStrokeColor, strokeWidth: 0.5, strokeDasharray: 0.2, fill: "none" })), _jsx("text", { x: x, y: y, fill: roseStrokeColor, textAnchor: "middle", fontSize: 10, dominantBaseline: "middle", children: letter })] }, letter));
|
|
20
|
+
})] }, row.join(""))))] })), debug && (_jsx("path", {
|
|
21
|
+
// Letter centres before optimisation
|
|
22
|
+
stroke: "#aa0", fill: "none", d: pathFromPoints({
|
|
23
|
+
points: sigilPoints(text, version),
|
|
24
|
+
sigilTokens,
|
|
25
|
+
}) })), _jsx("path", {
|
|
26
|
+
// Connecting path
|
|
27
|
+
stroke: "red", fill: "none", ref: pathRef, d: pathFromPoints({ points, sigilTokens }) })] }));
|
|
28
|
+
}
|
|
29
|
+
export default RoseSigilImage;
|