Skip to content

Instantly share code, notes, and snippets.

@leegee
Created February 1, 2024 10:03
Show Gist options
  • Save leegee/3ea08703ebf4333ebe4a89500a37d0da to your computer and use it in GitHub Desktop.
Save leegee/3ea08703ebf4333ebe4a89500a37d0da to your computer and use it in GitHub Desktop.
Kabbalah tree after Luria
<!DOCTYPE html>
<!-- still working on the paths, etc -->
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="theme-color" content="#000000">
<style>
html * {
box-sizing: border-box;
--clr-subtle-bg: #000;
--clr-bg: #222;
--clr-fg: whitesmoke;
--clr-fg-hilight: white;
--clr-border: #FFF5;
border-radius: 0.3em;
}
body {
background-color: black;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
overflow: visible;
border: 10pt solid var(--clr-subtle-bg);
}
svg {
z-index: 1;
border: none;
width: 100%;
height: 100%;
font-size: normal;
border: 1px dotted #FFF3;
}
svg * {
font-size: 1rem;
}
.sephira-group {
transition: transform 0.2s;
transform-box: fill-box;
display: block;
transform-origin: center center;
transition-delay: 0.15s;
}
.sephira-group:hover {
cursor: zoom-in;
transform: scale(1);
transition-delay: 0.1s;
}
.sephira-group:hover .bg {
fill: black;
}
.sephira-group.severity,
.sephira-group.mercy {
transform: scale(0.7);
}
.sephira-group.severity:hover,
.sephira-group.mercy:hover {
transform: scale(1);
}
.sephira-group .bg {
fill: transparent;
}
.sephira-group:hover .bg {
fill: black;
}
.sephira-group.einsof {
transform: translateY(-2rem);
}
.sephira-group.einsof foreignObject {
transform: translateY(-1rem);
}
.sephira-group.einsof .title {
font-size: 32pt;
opacity: 0.8;
}
.sephira-group.einsof .desc * {
font-size: 10pt !important;
padding: 0 !important;
margin: 0 !important;
}
.sephira-group.severity .order,
.sephira-group.mercy .order {
display: none;
}
.sephira-group.severity .title,
.sephira-group.mercy .title {
font-size: normal;
opacity: 0.7;
}
.sephira-group.severity .desc,
.sephira-group.mercy .desc {
transform: translateY(-0.2rem);
opacity: 0.4;
}
.sephira {
text-anchor: middle;
alignment-baseline: middle;
stroke: black;
stroke-width: 1px;
}
.order,
.title,
.desc {
text-anchor: middle;
alignment-baseline: middle;
fill: var(--clr-fg-hilight);
}
.desc {
fill: var(--clr-fg);
stroke: var(--clr-fg);
}
.order {
font-size: small;
transform: translateY(-1px);
fill: var(--clr-fg-hilight);
stroke: var(--clr-bg);
stroke-width: 0.5px;
opacity: 0.5;
}
:hover .order {
opacity: 1;
}
.title {
font-size: xx-large;
font-weight: bold;
stroke: black;
}
.foreignObjectRoot {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
font-family: Helvetica;
font-size: 10pt;
font-weight: lighter;
opacity: 70%;
color: var(--clr-fg);
flex-direction: column;
justify-content: flex-start;
}
.foreignObjectRoot p,
.foreignObjectRoot ul {
padding: 0;
margin: 0.4em 0 0.6em;
list-style: none;
text-align: center;
font-size: 50%;
}
.line-letter-path,
.text-path {
opacity: 33%;
transition: transform 0.2s;
transform-box: fill-box;
display: block;
transform-origin: center center;
text-anchor: middle;
alignment-baseline: middle;
}
.sephirot-outter-text-path {
stroke: none;
fill: var(--clr-fg);
opacity: 50%;
font-family: Helvetica;
font-size: x-small;
font-weight: lighter;
letter-spacing: -1px;
word-spacing: 0.7px;
transition: transform 0.2s;
transform-box: fill-box;
display: block;
transform-origin: center center;
text-anchor: middle;
alignment-baseline: before-edge;
}
.line-letter-path {
stroke-width: 1.3em;
}
.text-path {
fill: var(--clr-fg);
stroke: var(--clr-fg);
font-size: x-small;
}
.text-path-path:hover,
.line-letter-path:hover {
opacity: 1;
}
#pardes {
z-index: 1;
margin-right: 2em;
padding: 1em;
list-style: none;
font-size: 12pt;
background: var(--clr-subtle-bg);
opacity: 0.8;
transition: all 0.6s;
}
#pardes:hover {
opacity: 1;
}
#pardes div {
padding: 0.5rem;
margin: 0.5rem;
border: 1pt solid gray;
box-shadow: 0 0 4pt 4pt #6664;
opacity: 0.6;
transition: all 0.6s;
}
#pardes div:hover {
box-shadow: 0 0 4pt 4pt #6666;
opacity: 1;
transition: all 0.6s;
cursor: pointer;
}
/* Highlight only the pardes key selected on the body element */
body.pardes-peshat #peshat,
body.pardes-remez #remez,
body.pardes-derash #derash,
body.pardes-sod #sod {
opacity: 0.9 !important;
}
#pardes dt {
letter-spacing: 200%;
font-variant: small-caps;
color: var(--clr-fg);
display: flex;
justify-content: space-between;
align-items: center;
}
#pardes dt [lang=en] {
font-weight: normal;
float: left;
}
#pardes dt [lang=he] {
font-weight: bold;
float: right;
font-size: 4vh;
}
#pardes dd {
color: var(--clr-fg);
font-weight: light;
letter-spacing: normal;
padding: 0;
margin: 0.3em 0 1em;
}
#detail {
z-index: 100;
position: fixed;
top: 0;
left: 0;
width: 95vw;
height: 95vh;
padding: 2.5vh 2.5vw;
margin: 2.5vh 2.5vw;
border: 1pt solid #FFF6;
background-color: black;
color: var(--clr-fg);
font-size: large;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
display: none;
}
#detail * {
margin: 0;
padding: 0;
}
#detail.active {
display: flex;
}
#detail #Order {
font-size: 12pt;
width: 10em;
height: 2em;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 33pt;
border-bottom: 1px solid var(--clr-border);
position: relative;
top: -2em;
}
#detail #Hebrew {
font-size: 15vh;
margin-bottom: 0.3em;
}
#detail #Translit {
font-size: 5vh;
}
#detail #English {
font-size: 2.5vh;
font-style: italic;
opacity: 0.7;
}
#detail #Attr {
font-size: 200%;
margin: 2em 0;
}
#detail #Attr ul {
list-style-position: inside;
list-style-type: none;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 100%;
}
#detail #Attr li {
display: inline;
text-transform: capitalize;
}
#detail #Attr li:not(:first-child)::before {
content: "\2022";
margin-left: 1em;
margin-right: 1em;
}
#detail #Letter {
font-size: 5vh;
}
#detail #LetterName {
opacity: 0.5;
font-size: 2.5vh;
font-style: italic;
}
#detail #close-detail {
font-size: 10pt;
font-family: Helvetica, sans-serif;
text-transform: capitalize;
margin-top: 66pt;
border-top: 1px solid var(--clr-border);
padding: 33pt;
cursor: pointer;
opacity: 0.5;
}
#detail #close-detail:before {
margin-right: 0.5em;
content: '◀';
}
#detail #close-detail span {
padding: 1em;
display: inline-block;
}
#detail #close-detail:hover {
opacity: 1;
background-color: #FFF2;
border: 1px solid #FFF2;
}
/** For the pardesh:
* CSS classes for each element .pardes-peshat, .pardes-*.
* Dynamic CSS clasa applied to the body: .pardes-peshat, .pardes-*.
* CCS rule engaged when body.class='pardes.*'
*/
body>.pardes-peshat,
body>.pardes-remez,
body>.pardes-deresh,
body>.pardes-sod {
display: none;
}
body.pardes-peshat .pardes-peshat,
body.pardes-remez .pardes-remez,
body.pardes-deresh .pardes-deresh,
body.pardes-sod .pardes-sod {
display: block;
}
</style>
</head>
<body>
<template id="detail-template">
<p id="Order"></p>
<h2 id="Hebrew"></h2>
<p id="Translit"></p>
<p id="English"></p>
<p id="Attr"></p>
<p id="Letter"></p>
<p id="LetterName"></p>
<a id="close-detail">BACK TO THE TREE</a>
</template>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="-250 -100 500 1000" id="svg">
<defs>
<radialGradient id="gradient-Keter">
<stop offset="30%" style="stop-color:white; stop-opacity:1" />
<stop offset="100%" style="stop-color:whitesmoke; stop-opacity:1" />
</radialGradient>
<radialGradient id="gradient-Chokhmah">
<stop offset="30%" style="stop-color:hsl(40, 1%, 56%); stop-opacity:1" />
<stop offset="100%" style="stop-color:hsl(40, 1%, 46%); stop-opacity:1" />
</radialGradient>
<radialGradient id="gradient-Binah">
<stop offset="30%" style="stop-color:black; stop-opacity:1" />
<stop offset="100%" style="stop-color:#333; stop-opacity:1" />
</radialGradient>
<radialGradient id="gradient-Chesed">
<stop offset="30%" style="stop-color:hsl(209, 43%, 55%); stop-opacity:1" />
<stop offset="100%" style="stop-color:hsl(209, 33%, 45%); stop-opacity:1" />
</radialGradient>
<radialGradient id="gradient-Geburah">
<stop offset="30%" style="stop-color:hsl(5, 57%, 59%); stop-opacity:1" />
<stop offset="100%" style="stop-color:hsl(5, 47%, 49%); stop-opacity:1" />
</radialGradient>
<radialGradient id="gradient-Tiferet">
<stop offset="30%" style="stop-color:hsl(60, 100%, 50%); stop-opacity:1" />
<stop offset="100%" style="stop-color:hsl(60, 100%, 40%); stop-opacity:1" />
</radialGradient>
<radialGradient id="gradient-Netzach">
<stop offset="30%" style="stop-color:hsl(124, 26%, 52%); stop-opacity:1" />
<stop offset="100%" style="stop-color:hsl(124, 26%, 42%); stop-opacity:1" />
</radialGradient>
<radialGradient id="gradient-Hod">
<stop offset="30%" style="stop-color:hsl(33, 74%, 63%); stop-opacity:1" />
<stop offset="100%" style="stop-color:hsl(33, 64%, 53%); stop-opacity:1" />
</radialGradient>
<radialGradient id="gradient-Yesod">
<stop offset="30%" style="stop-color:hsl(260, 28%, 59%); stop-opacity:1" />
<stop offset="100%" style="stop-color:hsl(260, 28%, 49%); stop-opacity:1" />
</radialGradient>
<radialGradient id="gradient-Malkhut">
<stop offset="40%" style="stop-color:yellow; stop-opacity:1" />
<stop offset="85%" style="stop-color:green; stop-opacity:1" />
<stop offset="90%" style="stop-color:black; stop-opacity:1" />
<stop offset="95%" style="stop-color:red; stop-opacity:1" />
</radialGradient>
<filter id="drop-shadow">
<feGaussianBlur in="SourceAlpha" stdDeviation="4" />
<feOffset dx="0" dy="4" result="offsetblur" />
<feFlood flood-color="rgba(0, 0, 0, 0.2)" />
<feComposite in2="offsetblur" operator="in" />
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
</svg>
<aside id="detail"></aside>
<aside>
<menu id="pardes" alt='פרד"ס'>
<div id="peshat">
<dt><span lang="en">Peshat</span><span lang="he">פְּשָׁט</span></dt>
<dd>"surface" ("straight"); the literal, direct meaning.</dd>
</div>
<div id="remez">
<dt><span lang="en">Remez</span><span lang="he">רֶמֶז</span></dt>
<dd>"hints" ("deep"); allegorically hidden or symbolic meaning.</dd>
</div>
<div id="derash">
<dt><span lang="en">Derash</span><span lang="he">דְּרַשׁ</span></dt>
<dd>from Hebrew darash, "inquire" ("seek"); the comparative meaning, as given through
textual analysis of similar occurrences, aka Midrashic.</dd>
</div>
<div id="sod">
<dt><span lang="en">Sod</span><span lang="he">סוֹד</span></dt>
<dd>"secret" ("mystery"); the esoteric/mystical meaning,
as given through inspiration or revelation. </dd>
</div>
</menu>
</aside>
<script>
const templateEl = document.getElementById( 'detail-template' );
const detailEl = document.getElementById( 'detail' );
const RADIUS = 36;
const RADIUS_SMALLER = 30;
const X_PAD = 100;
const Y_PAD = 100;
let __currentPardes;
function showDetail ( sephiraData, _e ) {
const clone = document.importNode( templateEl.content, true );
for ( let attrName in sephiraData ) {
const el = clone.getElementById( attrName );
if ( el ) {
if ( typeof sephiraData[ attrName ] === 'string' || typeof sephiraData[ attrName ] === 'number' ) {
el.textContent = sephiraData[ attrName ];
}
else if ( sephiraData[ attrName ] instanceof Array ) {
el.innerHTML = '<ul>' + (
sephiraData[ attrName ].map( _ => { return `<li>${ _ }</li>` } ).join( '' )
) + '</ul>';
}
}
}
document.body.addEventListener( 'keydown', ( e ) => escClosesDetail( e, detailEl ) );
clone.querySelector( '#close-detail' ).addEventListener( 'click', () => {
closeDetail( detailEl );
document.removeEventListener( 'keydown', ( e ) => escClosesDetail( e, detailEl ) );
} );
clone.querySelector( '#Hebrew' ).style.filter = 'url("#gradient-' + sephiraData.Translit + '")';
closeDetail( detailEl );
detailEl.appendChild( clone );
detailEl.classList.add( 'active' );
}
function escClosesDetail ( e, detailEl ) {
if ( e.key === 'Esc' || e.key === 'Escape' ) {
closeDetail( detailEl );
}
}
function closeDetail ( detailEl ) {
detailEl.classList.remove( 'active' );
detailEl.innerHTML = '';
}
function foreignObject ( { id, xhtml, klass, x, y, width, height } ) {
const foreignObject = document.createElementNS( 'http://www.w3.org/2000/svg', 'foreignObject' );
foreignObject.id = id;
foreignObject.setAttribute( 'x', x );
foreignObject.setAttribute( 'y', y );
foreignObject.setAttribute( 'width', width );
foreignObject.setAttribute( 'height', height );
const body = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'div' );
body.setAttribute( 'xmlns', 'http://www.w3.org/1999/xhtml' );
body.setAttribute( 'class', klass + ' ' + 'foreignObjectRoot' );
body.innerHTML = xhtml;
foreignObject.appendChild( body );
return foreignObject;
}
function setPardes ( newPardes ) {
if ( __currentPardes ) {
document.body.classList.remove( __currentPardes );
}
__currentPardes = 'pardes-' + newPardes.toLowerCase();
document.body.classList.add( __currentPardes );
}
function addLines ( svgRootNode ) {
// Paths between sephira:
let lineCount = 0;
for ( const connection of connections ) {
const fromPosition = fromTreeOfLife( connection.from ).Position;
const toPosition = fromTreeOfLife( connection.to ).Position;
const lineId = `line${ ++lineCount }`;
// Create a line element
const lineNode = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
lineNode.setAttribute( 'id', lineId );
lineNode.setAttribute( 'class', 'line-letter-path' );
lineNode.setAttribute( 'd', `
M ${ fromPosition.x() },${ fromPosition.y() }
L ${ toPosition.x() },${ toPosition.y() }
` );
lineNode.setAttribute( 'stroke', connection.Color );
lineNode.setAttribute( 'fill', connection.Color );
svgRootNode.appendChild( lineNode );
// Create a textPath element to label the line
const textPathNode = document.createElementNS( 'http://www.w3.org/2000/svg', 'textPath' );
textPathNode.setAttribute( 'xlink:href', `#${ lineId }` );
textPathNode.setAttribute( 'class', 'text-path' );
textPathNode.textContent = connection.Letter;
// Create a text element and append the textPath
const textNode = document.createElementNS( 'http://www.w3.org/2000/svg', 'text' );
textNode.setAttribute( 'dx', '400%' );
textNode.appendChild( textPathNode );
svgRootNode.appendChild( textNode );
}
}
function addSephirot ( svgRootNode ) {
// Render sephirot
let circleLines = 0;
for ( const sephira in treeOfLife ) {
const sephiraData = treeOfLife[ sephira ];
const cx = sephiraData.Position.x();
const cy = sephiraData.Position.y();
const circleId = 'circle-' + ( ++circleLines );
// Create a <g> to group all sephirot
const sephiraGroup = document.createElementNS( 'http://www.w3.org/2000/svg', 'g' );
sephiraGroup.setAttribute( 'class', 'sephira-group ' + ( sephira.toLowerCase() ) );
sephiraGroup.addEventListener( 'click', ( e ) => showDetail( sephiraData, e ) );
svgRootNode.appendChild( sephiraGroup );
// Create the sephira sphere and append it to the <g> element
const path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
path.setAttribute( 'id', circleId );
path.setAttribute( "d", `
M ${ cx },${ cy - RADIUS_SMALLER }
A ${ RADIUS_SMALLER },${ RADIUS_SMALLER } 0 1,0 ${ cx },${ cy + RADIUS_SMALLER }
A ${ RADIUS_SMALLER },${ RADIUS_SMALLER } 0 1,0 ${ cx },${ cy - RADIUS_SMALLER }
`);
path.setAttribute( 'stroke', sephiraData.Translit );
path.setAttribute( 'fill', `url(#gradient-${ sephiraData.Translit })` );
path.setAttribute( 'filter', 'url(#drop-shadow)' );
path.setAttribute( 'class', 'sephira' );
sephiraGroup.appendChild( path );
// Put the Number at the top of the sphere
const number = document.createElementNS( 'http://www.w3.org/2000/svg', 'text' );
number.setAttribute( 'class', 'order' );
number.setAttribute( 'x', sephiraData.Position.x() );
number.setAttribute( 'y', sephiraData.Position.y() - ( RADIUS / 1.9 ) );
number.textContent = `${ sephiraData.Order }`;
sephiraGroup.appendChild( number );
// Create a title text and append it to the <g> element
const title = document.createElementNS( 'http://www.w3.org/2000/svg', 'text' );
title.setAttribute( 'class', 'title' );
title.setAttribute( 'x', sephiraData.Position.x() );
title.setAttribute( 'y', sephiraData.Position.y() );
title.setAttribute( 'filter', 'url(#drop-shadow)' );
title.textContent = `${ sephiraData.Hebrew }`;
sephiraGroup.appendChild( title );
// Create a description text and append it to the <g> element
// const desc = document.createElementNS( 'http://www.w3.org/2000/svg', 'text' );
// desc.setAttribute( 'class', 'desc' );
// desc.setAttribute( 'x', sephiraData.Position.x() );
// desc.setAttribute( 'y', sephiraData.Position.y() + ( RADIUS + 15 ) );
// desc.textContent = `${ sephiraData.Translit } (${ sephiraData.English }) · ${ sephiraData.Letter }`;
// sephiraGroup.appendChild( desc );
// Pardes
for ( let pardes of [ 'peshat', 'remez', 'derash', 'sod' ] ) {
const xhtml = `<ul><li>${ sephiraData.Translit } (${ sephiraData.English })</li><li>${ sephiraData.Letter }</li>`;
sephiraGroup.appendChild(
foreignObject( {
x: sephiraData.Position.x() - ( RADIUS * 2.5 ),
y: sephiraData.Position.y() + ( RADIUS / 0.9 ),
width: RADIUS * 5,
height: RADIUS * 2,
klass: 'desc pardes-' + pardes,
xhtml: xhtml
} )
);
}
// TextPath: wrap some text around the same path as the circle: @see associated CSS
const textPathNode = document.createElementNS( 'http://www.w3.org/2000/svg', 'textPath' );
textPathNode.setAttribute( 'href', `#${ circleId }` );
textPathNode.setAttribute( 'class', 'sephirot-outter-text-path' );
textPathNode.setAttribute( 'startOffset', '50%' );
textPathNode.textContent = sephiraData.Attr.join( ' ' );
// Create a text element and append to the textPath created above
const textNode = document.createElementNS( 'http://www.w3.org/2000/svg', 'text' );
textNode.appendChild( textPathNode );
sephiraGroup.appendChild( textNode );
// Get the bounding box (size) of the <g> element
const bbox = sephiraGroup.getBBox();
// and create a <rect> element to match the size
if ( !sephiraData.noBg ) {
const rect = document.createElementNS( 'http://www.w3.org/2000/svg', 'rect' );
rect.setAttribute( 'x', bbox.x - ( RADIUS / 2 ) );
rect.setAttribute( 'y', bbox.y - ( RADIUS / 2 ) );
rect.setAttribute( 'width', bbox.width + ( RADIUS * 2 ) );
rect.setAttribute( 'height', bbox.height + ( RADIUS * 2 ) );
rect.setAttribute( 'class', 'bg' );
// Insert the <rect> as the first child of the <g> element
sephiraGroup.insertBefore( rect, sephiraGroup.firstChild );
}
}
}
function addPardes ( pardes ) {
setPardes( 'peshat' );
document.getElementById( 'pardes' ).addEventListener( 'click', ( e ) => {
setPardes( String(
e.target.id || e.target.parentElement.id || e.target.parentElement.parentElement.id
).toLowerCase() );
} );
}
function createSvg () {
const svg = document.getElementById( 'svg' );
const svgRootNode = document.createElementNS( 'http://www.w3.org/2000/svg', 'g' );
svg.appendChild( svgRootNode );
return svgRootNode;
}
const fromTreeOfLife = sephiraTranslitName => treeOfLife[ sephiraTranslitName ];
const treeOfLife = {
EinSof: {
Order: 0,
Hebrew: 'אֵין סוֹף אוֹר',
Translit: 'Ohr Ein Sof, Ein Sof, Ein',
English: 'Limitless Light, Limitless, Nothing',
Letter: ' ',
LetterName: ' ',
Attr: [],
Position: {
x: () => 0,
y: () => -1 * RADIUS,
},
},
Keter: {
Order: 1,
Hebrew: 'כֶּתֶר',
Translit: 'Keter',
English: 'Crown',
Letter: 'א',
LetterName: 'Aleph',
Attr: [ 'crown', 'aura', 'yechidah' ],
Position: {
x: () => fromTreeOfLife( 'EinSof' ).Position.x(),
y: () => fromTreeOfLife( 'EinSof' ).Position.y() + Y_PAD,
},
},
Mercy: {
noBg: true,
Order: 1,
Hebrew: 'יָכִין',
Translit: 'Yakin',
English: 'Mercy',
Letter: '',
LetterName: '',
Attr: [ '' ],
Position: {
x: () => fromTreeOfLife( 'Keter' ).Position.x() + ( 1.6 * X_PAD ),
y: () => fromTreeOfLife( 'Keter' ).Position.y(),
},
},
Severity: {
noBg: true,
Order: 1,
Hebrew: 'בועז',
Translit: 'Boaz',
English: 'Severity',
Letter: '',
LetterName: '',
Attr: [ '' ],
Position: {
x: () => fromTreeOfLife( 'Keter' ).Position.x() - ( 1.6 * X_PAD ),
y: () => fromTreeOfLife( 'Keter' ).Position.y(),
},
},
Chokhmah: {
Order: 2,
Hebrew: 'חָכְמָה',
Translit: 'Chokhmah',
English: 'Wisdom',
Letter: 'ב',
LetterName: 'Bet',
Attr: [ 'wisdom', 'face of the hashem', 'chiam' ],
Position: {
x: () => fromTreeOfLife( 'Keter' ).Position.x() + X_PAD,
y: () => fromTreeOfLife( 'Keter' ).Position.y() + Y_PAD,
},
},
Binah: {
Order: 2,
Hebrew: 'בִּינָה',
Translit: 'Binah',
English: 'Understanding',
Letter: 'ג',
LetterName: 'Gimel',
Color: 'black',
Attr: [ 'understanding', 'mother', 'neschamah' ],
Position: {
x: () => fromTreeOfLife( 'Keter' ).Position.x() - X_PAD,
y: () => fromTreeOfLife( 'Keter' ).Position.y() + Y_PAD,
},
},
Chesed: {
Order: 4,
Hebrew: 'חֶסֶד',
Translit: 'Chesed',
English: 'Kindness',
Letter: 'ד',
LetterName: 'Dalet',
Color: 'turquoise',
Attr: [ 'hashem mercy', 'majesty', 'vision of love' ],
Position: {
x: () => fromTreeOfLife( 'Chokhmah' ).Position.x(),
y: () => fromTreeOfLife( 'Chokhmah' ).Position.y() + ( Y_PAD * 1.5 ),
},
},
Geburah: {
Order: 5,
Hebrew: 'גְּבוּרָה',
Translit: 'Geburah',
English: 'Severity',
Letter: 'ה',
LetterName: 'Hey',
Color: 'hsl(39, 71%, 48%)',
Attr: [ 'strength', 'vision of power', 'force' ],
Position: {
x: () => fromTreeOfLife( 'Binah' ).Position.x(),
y: () => fromTreeOfLife( 'Binah' ).Position.y() + ( Y_PAD * 1.5 ),
},
},
Tiferet: {
Order: 6,
Hebrew: 'תִּפְאֶרֶת',
Translit: 'Tiferet',
English: 'Beauty',
Letter: 'ו',
LetterName: 'Vav',
Attr: [ 'beauty', 'harmony', 'breath' ],
Position: {
x: () => fromTreeOfLife( 'Keter' ).Position.x(),
y: () => fromTreeOfLife( 'Chesed' ).Position.y() + Y_PAD,
},
},
Netzach: {
Order: 7,
Hebrew: 'נֵצַח',
Translit: 'Netzach',
English: 'Eternity',
Letter: 'ז',
LetterName: 'Zayin',
Color: 'hsl(120, 85%, 39%)',
Attr: [ 'victory', 'eternity', 'triumph' ],
Position: {
x: () => fromTreeOfLife( 'Tiferet' ).Position.x() + X_PAD,
y: () => fromTreeOfLife( 'Tiferet' ).Position.y() + Y_PAD,
},
},
Hod: {
Order: 8,
Hebrew: 'הוֹד',
Translit: 'Hod',
English: 'Glory',
Letter: 'ח',
LetterName: 'Chet',
Color: 'hsl(51, 100%, 50%)',
Attr: [ 'images of hashem', 'truthfulness', 'splendor' ],
Position: {
x: () => fromTreeOfLife( 'Tiferet' ).Position.x() - X_PAD,
y: () => fromTreeOfLife( 'Tiferet' ).Position.y() + Y_PAD,
},
},
Yesod: {
Order: 9,
Hebrew: 'יְסוֹד',
Translit: 'Yesod',
English: 'Foundation',
Letter: 'ט',
LetterName: 'Tet',
Color: 'purple',
Attr: [ 'foundation', 'astral light', 'nepesch' ],
Position: {
x: () => fromTreeOfLife( 'Keter' ).Position.x(),
y: () => fromTreeOfLife( 'Hod' ).Position.y() + Y_PAD,
},
},
Malkhut: {
Order: 10,
Hebrew: 'מַלְכוּת',
Translit: 'Malkhut',
English: 'Kingdom',
Letter: 'י',
LetterName: 'Yod',
Color: 'white',
Attr: [ 'kingdom', 'mystic circle', 'guph!' ],
Position: {
x: () => fromTreeOfLife( 'Keter' ).Position.x(),
y: () => fromTreeOfLife( 'Yesod' ).Position.y() + ( Y_PAD * 1.2 ),
},
},
};
const connections = [
{
from: 'Keter',
to: 'Chokhmah',
LetterName: 'Aleph',
Color: '#0000FF',
Letter: 'א',
},
{
from: 'Keter',
to: 'Binah',
LetterName: 'Bet',
Color: '#0000FF',
Letter: 'ב',
},
{
from: 'Chokhmah',
to: 'Chesed',
LetterName: 'Vav',
Color: '#0000FF',
Letter: 'ו',
},
{
from: 'Chokhmah',
to: 'Binah',
LetterName: 'Dalet',
Color: '#0000FF',
Letter: 'ד',
},
{
from: 'Geburah',
to: 'Hod',
LetterName: 'Mem',
Color: '#0000FF',
Letter: 'מ',
},
{
from: 'Chesed',
to: 'Geburah',
LetterName: 'Tet',
Color: '#0000FF',
Letter: 'ט',
},
{
from: 'Chesed',
to: 'Netzach',
LetterName: 'Kaf',
Color: '#0000FF',
Letter: 'כ',
},
{
from: 'Geburah',
to: 'Tiferet',
LetterName: 'Yod',
Color: '#0000FF',
Letter: 'י',
},
{
from: 'Chesed',
to: 'Tiferet',
LetterName: 'Lamed',
Color: '#0000FF',
Letter: 'ל',
},
{
from: 'Tiferet',
to: 'Netzach',
LetterName: 'Nun',
Color: '#0000FF',
Letter: 'נ',
},
{
from: 'Tiferet',
to: 'Hod',
LetterName: 'Ayin',
Color: '#0000FF',
Letter: 'ע',
},
{
from: 'Netzach',
to: 'Hod',
LetterName: 'Peh',
Color: '#0000FF',
Letter: 'פ',
},
{
from: 'Netzach',
to: 'Yesod',
LetterName: 'Tzadi',
Color: '#0000FF',
Letter: 'צ',
},
{
from: 'Hod',
to: 'Yesod',
LetterName: 'Resh',
Color: '#0000FF',
Letter: 'ר',
},
{
from: 'Yesod',
to: 'Malkhut',
LetterName: 'Tav',
Color: '#0000FF',
Letter: 'ת',
},
{
from: 'Binah',
to: 'Geburah',
LetterName: 'Chet',
Color: '#0000FF',
Letter: 'ח',
},
];
const svgRootNode = createSvg();
addLines( svgRootNode );
addSephirot( svgRootNode );
addPardes( 'peshat' );
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment