Skip to content

Visual

Import

import {
// Astro wheel
generateAstroWheelSvg,
getAstroWheelRenderModel,
ASTRO_WHEEL_DEFAULT_VIEWBOX,
ASTRO_WHEEL_DEFAULT_ASPECT_SPECS,
ASTRO_WHEEL_ZODIAC_SIGNS,
ASTRO_WHEEL_POINT_GLYPHS,
// Glyphs
generateGlyphSvg,
generateAstroGlyphSvg,
getAstroGlyph,
listAstroGlyphs,
ZODIAC_GLYPHS,
PLANET_GLYPHS,
ASPECT_GLYPHS,
ANGLE_GLYPHS,
ZODIAC_GLYPH_PRIMITIVES,
PLANET_GLYPH_PRIMITIVES,
ASPECT_GLYPH_PRIMITIVES,
// Archeometer
generateArcheometerSvg,
getArcheometerRenderModel,
ARCHEOMETER_DEFAULT_VIEWBOX,
DEFAULT_ARCHEOMETER_UTTERANCE,
// Tree of Life
generateTreeSvg,
getTreeLayout,
getTreeRenderModel,
TREE_SVG_DEFAULT_VIEWBOX,
TREE_SPHERE_NAMES,
TREE_SPHERE_IDS,
TREE_PATH_IDS,
} from 'kaabalah/visual';

Exports

  • generateAstroWheelSvg
  • getAstroWheelRenderModel
  • generateGlyphSvg
  • generateAstroGlyphSvg
  • getAstroGlyph
  • listAstroGlyphs
  • ASTRO_WHEEL_DEFAULT_VIEWBOX
  • ASTRO_WHEEL_DEFAULT_ASPECT_SPECS
  • ASTRO_WHEEL_ZODIAC_SIGNS
  • ASTRO_WHEEL_POINT_GLYPHS
  • ZODIAC_GLYPHS
  • PLANET_GLYPHS
  • ASPECT_GLYPHS
  • ANGLE_GLYPHS
  • ZODIAC_GLYPH_PRIMITIVES
  • PLANET_GLYPH_PRIMITIVES
  • ASPECT_GLYPH_PRIMITIVES
  • generateArcheometerSvg
  • getArcheometerRenderModel
  • ARCHEOMETER_DEFAULT_VIEWBOX
  • DEFAULT_ARCHEOMETER_UTTERANCE
  • DEFAULT_ARCHEOMETER_TRIANGLES
  • DEFAULT_ARCHEOMETER_MUSICAL_NOTES
  • DEFAULT_ARCHEOMETER_ZODIAC
  • DEFAULT_ARCHEOMETER_PLANETS
  • generateTreeSvg
  • getTreeLayout
  • getTreeRenderModel
  • TREE_SVG_DEFAULT_VIEWBOX
  • TREE_SPHERE_NAMES
  • TREE_SPHERE_IDS
  • TREE_PATH_IDS
  • Types: AstroGlyphPrimitive, GlyphSvgOptions, AstroWheelPlanetGlyphKey, AstroWheelAspectGlyphKey, AstroWheelSvgOptions, AstroWheelPalette, AstroWheelPaletteOverrides, AstroWheelZodiacOptions, AstroWheelAspectOptions, AstroWheelHouseOptions, AstroWheelPointOptions, AstroWheelLayoutOptions, AstroWheelPointConnectorMode, AstroWheelPointLayerInput, AstroWheelAspectLayerInput, AstroWheelPointSource, AstroWheelViewBox, AstroWheelRenderModel, AstroWheelZodiacSegment, AstroWheelHouseCusp, AstroWheelAngleMarker, AstroWheelPoint, AstroWheelArcConnector, AstroWheelPointLayer, AstroWheelAspectLine, AstroWheelAspectLayer, ArcheometerSvgOptions, ArcheometerPalette, ArcheometerPaletteOverrides, ArcheometerRenderModel, ArcheometerRing, ArcheometerRingId, ArcheometerUtterancePoint, ArcheometerTriangleSpec, ArcheometerTriangleLabel, ArcheometerMusicalNote, ArcheometerZodiacSign, ArcheometerPlanetaryPoint, TreeSvgOptions, TreeSvgPalette, TreeSvgCustomPalette, TreeSvgHighlights, TreeTargetActivationInput, TreeTargetState, TreeSvgDaathLayer, TreeSvgViewBox, TreeLayout, TreeLayoutMap, TreeLayoutPath, TreeLayoutCoordinate, TreeRenderModel, TreeRenderSphere, TreeRenderPath, TreeRenderSphereGeometry, TreeRenderPathGeometry, TreeRenderHitTarget, TreeRenderAnchor, TreeSphereName, TreeSphereId, TreePathId

Astrology Wheel

generateAstroWheelSvg(chart, options?)

Renders a complete radial astrology wheel as an SVG string from a BirthChart returned by kaabalah/astrology. The output contains zodiac sign segments colored by element, house cusp lines, planet and node glyphs positioned around the wheel, and aspect lines connecting related planets. Part of Fortune and Vertex are included automatically when the chart provides them.

function generateAstroWheelSvg(chart: BirthChart, options?: AstroWheelSvgOptions): string

Basic usage

import { getBirthChart, HouseSystem } from 'kaabalah/astrology';
import { generateAstroWheelSvg } from 'kaabalah/visual';
const chart = await getBirthChart({
date: { year: 1990, month: 1, day: 1, hour: 12, minute: 0 },
latitude: 40.7128,
longitude: -74.006,
houseSystem: HouseSystem.PLACIDUS,
timeZoneSettings: { timeZone: "America/New_York" },
});
const svg = generateAstroWheelSvg(chart, {
width: 600,
height: 600,
background: "transparent",
});

The returned string can be written to a .svg file, embedded in an HTML page, or used as the base layer below custom overlays. No React, DOM, or WASM runtime is required by the visual renderer itself — the only input is the already-computed BirthChart.

Default astrology wheel

AstroWheelSvgOptions

interface AstroWheelSvgOptions {
width?: number | string;
height?: number | string;
viewBox?: AstroWheelViewBox; // default: 0 0 600 600
background?: string | "transparent"; // default: "transparent"
palette?: AstroWheelPalette;
zodiac?: boolean | AstroWheelZodiacOptions; // segments/glyphs/ticks
aspects?: boolean | AstroWheelAspectOptions; // default: true
houses?: boolean | AstroWheelHouseOptions; // labels/cusp lines/angle labels
points?: boolean | AstroWheelPointOptions; // birth planets/nodes/vertex
pointLayers?: readonly AstroWheelPointLayerInput[];
aspectLayers?: readonly AstroWheelAspectLayerInput[];
excludeBodies?: readonly string[]; // render-only body filter
layout?: AstroWheelLayoutOptions; // ring proportions/connectors
padding?: number;
title?: string;
}

Layer controls

Each visual layer is independent. Toggle any layer off without affecting the others:

generateAstroWheelSvg(chart, { zodiac: false }); // strip zodiac segments, glyphs, and ticks
generateAstroWheelSvg(chart, { houses: false }); // strip house cusps and ASC/MC labels
generateAstroWheelSvg(chart, { points: false }); // strip birth planets/nodes/vertex
generateAstroWheelSvg(chart, { aspects: false }); // strip aspect lines
generateAstroWheelSvg(chart, {
zodiac: { glyphs: false }, // keep colored sign segments and ticks
houses: { labels: false }, // keep cusp lines, hide house numbers
points: {
nodes: false, // keep planets, hide nodes
collisionThresholdDegrees: 6,
},
});

Use excludeBodies when an app needs the full BirthChart for other panels but wants the wheel itself to omit specific bodies and their aspect lines:

generateAstroWheelSvg(chart, {
excludeBodies: ["True Node", "Lilith True"],
});

Planet labels are rendered in the final SVG glyph layer with halos and inline position text (planet glyph, degree, sign glyph, minutes). Override palette.glyphHalo when the automatic halo color should not match the wheel background.

Wheel layout

Use layout when the default wheel proportions or displaced-label connectors need tuning. The default ring fractions are houses: 7, zodiac: 13, planets: 27, and aspects: 53.

const svg = generateAstroWheelSvg(chart, {
layout: {
rings: {
planets: 32,
aspects: 48,
},
pointConnectors: "auto", // "auto" | "always" | "never"
maxPointDisplacementDegrees: 20,
},
});

Planet ticks and aspect lines use true astronomical longitude. When clustered planet labels are spread for readability, only the visual label angle changes. If connectors are enabled, the radial tick ends on the planet glyph rail, then the renderer draws an arc along that same imaginary circle toward the displaced glyph instead of a straight chord through the wheel.

Aspect orbs

Pass aspectSpecs to override which aspects are drawn and their orbs. The renderer recomputes planet-to-planet aspects from the chart positions:

const svg = generateAstroWheelSvg(chart, {
aspects: {
aspectSpecs: [
{ name: "conjunction", angle: 0, orb: 6 },
{ name: "opposition", angle: 180, orb: 7 },
],
},
});

Composable overlays

pointLayers and aspectLayers let you compose transits, synastry, or any custom calculated points over a base chart without rebuilding the SVG. Extra point layers share the base chart’s Ascendant orientation and can be placed inside, on, or outside the normal planet ring.

const svg = generateAstroWheelSvg(birthChart, {
pointLayers: [
{
id: "transit",
label: "Transits",
chart: transitChart,
color: "#f97316",
radius: "outer",
radiusOffset: 24,
glyphScale: 0.85,
},
],
aspectLayers: [
{
id: "transit",
label: "Transit aspects",
chart: transitChart,
pointLayerId: "transit",
color: "#f97316",
aspectSpecs: [
{ name: "conjunction", angle: 0, orb: 6 },
{ name: "opposition", angle: 180, orb: 7 },
],
radiusScale: 1.08,
},
{
id: "birth-transit",
label: "Birth to transit aspects",
edges: transitToBirthAspects,
pointLayerIdA: "birth",
pointLayerIdB: "transit",
color: "#7c3aed",
},
],
});

Use pointLayerIdA / pointLayerIdB with explicit edges for cross-chart lines (synastry, transit-to-birth). The shorthand pointLayerId: "transit" works when both endpoints come from the same overlay layer.

For fully custom overlays, pass points instead of chart:

const svg = generateAstroWheelSvg(birthChart, {
pointLayers: [
{
id: "progressed",
color: "#7c3aed",
points: [
{ key: "progressed-moon", name: "Progressed Moon", longitude: 214.5, glyph: "" },
],
},
],
});

Wheel comparison

Default palette wheel
”default” palette
Monochrome palette wheel
”monochrome” palette
Wheel with aspects hidden
aspects: false
Wheel with transit overlay
transit overlay

getAstroWheelRenderModel(chart, options?)

Returns the computed geometry for every element of the wheel without producing an SVG string. Use this when an app needs interactive overlays, hover targets, or custom tooltips without rebuilding wheel geometry.

import { getAstroWheelRenderModel } from 'kaabalah/visual';
const model = getAstroWheelRenderModel(chart);
model.viewBox; // { minX: 0, minY: 0, width: 600, height: 600 }
model.points; // planet/node glyph positions and exact tick lines
model.pointLayers; // grouped birth/transit/synastry/custom point layers
model.houseCusps; // cusp line geometry in SVG units
model.aspectLines; // aspect line geometry and colors
model.aspectLayers; // grouped aspect overlays

All coordinates live in the same SVG viewBox units as generateAstroWheelSvg(...), so overlays can be drawn in a sibling <svg> using the same viewBox and preserveAspectRatio="xMidYMid meet".


Glyphs

The visual module ships vector glyph definitions for zodiac signs, planets, aspects, and chart angles. The wheel renderer uses these same exported definitions, so downstream apps can render matching standalone icons or compose transit/synastry overlays without copying SVG files from the docs site.

getAstroGlyph(key) / listAstroGlyphs(category?)

Looks up reusable glyph definitions by canonical key or alias. Examples: "sun", "wheel-of-fortune", "quincunx", "asc".

import { getAstroGlyph, listAstroGlyphs } from 'kaabalah/visual';
const fortune = getAstroGlyph("wheel-of-fortune"); // PLANET_GLYPHS["pars fortunae"]
const aspects = listAstroGlyphs("aspect");

generateAstroGlyphSvg(keyOrGlyph, options?)

Renders a named glyph definition as a standalone SVG string.

import { generateAstroGlyphSvg } from 'kaabalah/visual';
const asc = generateAstroGlyphSvg("asc", { size: 48, color: "#b1468d" });
const quincunx = generateAstroGlyphSvg("quincunx", { size: 32 });

ZODIAC_GLYPHS, PLANET_GLYPHS, ASPECT_GLYPHS, ANGLE_GLYPHS

Exported glyph-definition maps. Each value has { key, label, category, primitives, aliases }. Angle glyphs include circled ASC/MC style markers and a plain Vx Vertex glyph.

The lower-level primitive maps remain exported for custom renderers that want direct drawing instructions.

generateGlyphSvg(primitives, options?)

Renders any glyph primitive array as a standalone SVG string.

function generateGlyphSvg(primitives: readonly AstroGlyphPrimitive[], options?: GlyphSvgOptions): string
interface GlyphSvgOptions {
size?: number; // default: 48
color?: string; // stroke color, default: "#111827"
strokeWidth?: number; // default: 0.14
fill?: "none" | string; // default: "none"
background?: string | "transparent"; // default: "transparent"
}
import { generateGlyphSvg, PLANET_GLYPH_PRIMITIVES } from 'kaabalah/visual';
const svg = generateGlyphSvg(PLANET_GLYPH_PRIMITIVES.sun, {
size: 64,
color: "#1f2933",
});

ZODIAC_GLYPH_PRIMITIVES

Vector primitives for all 12 zodiac signs. These are also used internally by the astrology wheel renderer for zodiac segment labels.

import { ZODIAC_GLYPH_PRIMITIVES } from 'kaabalah/visual';
ZODIAC_GLYPH_PRIMITIVES.Aries; // AstroGlyphPrimitive[]
ZODIAC_GLYPH_PRIMITIVES.Pisces;

PLANET_GLYPH_PRIMITIVES

Vector primitives for planets and special points.

import { PLANET_GLYPH_PRIMITIVES } from 'kaabalah/visual';
PLANET_GLYPH_PRIMITIVES.sun; // AstroGlyphPrimitive[]
PLANET_GLYPH_PRIMITIVES.saturn;
PLANET_GLYPH_PRIMITIVES["north node"];
PLANET_GLYPH_PRIMITIVES["pars fortunae"];

ASPECT_GLYPH_PRIMITIVES

Vector primitives for aspect symbols.

import { ASPECT_GLYPH_PRIMITIVES } from 'kaabalah/visual';
ASPECT_GLYPH_PRIMITIVES.conjunction; // AstroGlyphPrimitive[]
ASPECT_GLYPH_PRIMITIVES.trine;
ASPECT_GLYPH_PRIMITIVES.inconjunct;

ANGLE_GLYPHS

Reusable chart angle glyphs for overlay controls, legends, and custom chart layers.

AstroGlyphPrimitive

All glyph maps share the same primitive type:

type AstroGlyphPrimitive =
| { kind: "path"; d: string }
| { kind: "circle"; cx: number; cy: number; r: number }
| { kind: "line"; x1: number; y1: number; x2: number; y2: number }
| { kind: "polyline"; points: string }
| { kind: "text"; text: string; x?: number; y?: number; fontSize?: number; fontWeight?: string | number }
| { kind: "raw"; markup: string };

Coordinates are normalized to roughly -1…1. Scale and translate to your target viewport before rendering.


Archeometer

generateArcheometerSvg(options?)

Generates a complete Archeometer SVG string from deterministic render tables. The output contains the dual degree crown, utterance rings, trigone geometry, zodiac and planetary glyph rings, chromic rays, white rays, and solar center.

function generateArcheometerSvg(options?: ArcheometerSvgOptions): string

Basic usage

import { generateArcheometerSvg } from 'kaabalah/visual';
const svg = generateArcheometerSvg({
width: 900,
height: 900,
background: "transparent",
title: "The Cosmological Archeometer",
});
The Cosmological Archeometer

ArcheometerSvgOptions

interface ArcheometerSvgOptions {
width?: number | string;
height?: number | string;
viewBox?: ArcheometerSvgViewBox; // default: 0 0 900 900
background?: string | "transparent"; // default: "transparent"
palette?: ArcheometerPalette;
padding?: number;
rotationDegrees?: number; // 0 degrees is north; positive rotates clockwise
degreeLabelEvery?: number;
layers?: ArcheometerLayerOptions;
utterance?: readonly ArcheometerUtterancePoint[];
triangles?: readonly ArcheometerTriangleSpec[];
triangleLabels?: readonly ArcheometerTriangleLabel[];
musicalNotes?: readonly ArcheometerMusicalNote[];
zodiacSigns?: readonly ArcheometerZodiacSign[];
planetaryPoints?: readonly ArcheometerPlanetaryPoint[];
}

Use getArcheometerRenderModel() when you need the normalized ring geometry, resolved palette, and default correspondence tables without serializing SVG.

import { DEFAULT_ARCHEOMETER_UTTERANCE, generateArcheometerSvg } from 'kaabalah/visual';
const svg = generateArcheometerSvg({
utterance: DEFAULT_ARCHEOMETER_UTTERANCE.map((point) =>
point.id === "y"
? { ...point, letter: "Ya", number: 11, color: "#123456" }
: point
),
});

Tree of Life

generateTreeSvg(options?)

Generates a complete Tree of Life SVG string. The output contains 11 sphere circles and 22 path lines laid out on the canonical Kabbalistic grid, with radial gradient highlights baked in.

function generateTreeSvg(options?: TreeSvgOptions): string

All options are optional. Calling generateTreeSvg() with no arguments produces a full-color SVG at the default viewBox size with a white background.

TreeSvgOptions

interface TreeSvgOptions {
width?: number | string; // SVG width attribute (omitted if not set)
height?: number | string; // SVG height attribute (omitted if not set)
viewBox?: TreeSvgViewBox; // override coordinate space (default: 0 0 286 561)
background?: string | "transparent"; // fill color or "transparent" (default: "white")
palette?: TreeSvgPalette; // color scheme (default: "color")
system?: SystemKey; // "kaabalah" | "hermetic-qabalah" | "lurianic-kabbalah" (default: "kaabalah")
daathLayer?: TreeSvgDaathLayer; // "front" | "back" (default: "front")
highlights?: TreeSvgHighlights; // targeted path/sphere recolors layered on top of the base renderer
activations?: readonly TreeTargetActivationInput[]; // activation-aware prominence and hit geometry metadata
}

Basic usage

import { generateTreeSvg } from 'kaabalah/visual';
// Full-color SVG, white background, default size
const svg = generateTreeSvg();
// Monochrome, transparent background, explicit pixel dimensions
const svg = generateTreeSvg({
width: 400,
height: 785,
background: "transparent",
palette: "monochrome",
});
// Write to file (Node.js)
import { writeFileSync } from 'node:fs';
writeFileSync("tree.svg", generateTreeSvg({ background: "transparent" }));
Default color palette Tree of Life

ViewBox

The default coordinate space is 0 0 286 561 (exported as TREE_SVG_DEFAULT_VIEWBOX). You can override it without affecting the width/height pixel size — the SVG uses preserveAspectRatio="xMidYMid meet".

interface TreeSvgViewBox {
minX?: number; // default: 0
minY?: number; // default: 0
width: number;
height: number;
}
// Embed in a larger canvas with padding
const svg = generateTreeSvg({
viewBox: { minX: -20, minY: -20, width: 326, height: 601 },
});

Palette

TreeSvgPalette is a union of three forms:

type TreeSvgPalette = "color" | "monochrome" | TreeSvgCustomPalette;

"color" (default)

Sphere and path colors are read from the Tree of Life color data. Special spheres receive distinctive rendering:

  • Kether — white sunburst with radial facets
  • Chokhmah — iridescent shimmer
  • Daath — yin-yang symbol
  • Malkuth — four-quadrant color slices
  • Paths keep their layered treatment, with the outer edge rendered as a darker version of the path hue instead of a neutral outline.

"monochrome"

All spheres render in warm off-white (#e6ddd0) with dark outlines (#2f271e). Paths are uniform (#e0d7ca). Special sphere rendering is disabled.

Custom palette — TreeSvgCustomPalette

Fine-grained control over every visual element:

interface TreeSvgCustomPalette {
defaultSphereFill?: string;
defaultPathColor?: string;
sphereFills?: Partial<Record<TreeSphereId, string | string[]>>;
pathColors?: Partial<Record<TreePathId, string>>;
pathEdgeColor?: string;
sphereStrokeColor?: string;
sphereStrokeWidth?: number;
pathHighlightColor?: string;
pathHighlightOpacity?: number;
specialSphereMode?: "preserve" | "plain";
}

sphereFills accepts either a single hex string or an array of hex strings (used for multi-color rendering like Malkuth’s four quadrants). Unspecified spheres fall back to defaultSphereFill.

specialSphereMode:

  • "preserve" — Kether, Chokhmah, Daath, and Malkuth render with their special effects
  • "plain" — all spheres render as simple filled circles (default for custom palettes)
import { generateTreeSvg } from 'kaabalah/visual';
const svg = generateTreeSvg({
background: "#050315",
palette: {
defaultSphereFill: "#ffd700",
defaultPathColor: "#ffd700",
pathEdgeColor: "#2a2418",
sphereStrokeColor: "#2a2418",
sphereStrokeWidth: 2,
specialSphereMode: "plain",
},
});

Palette comparison

Color palette
”color” (default)
Monochrome palette
“monochrome”
Custom gold palette
custom (gold)

Highlights

highlights is the additive way to selectively recolor only the paths and spheres you care about while leaving every unmentioned element exactly as the current renderer would draw it.

interface TreeSvgHighlights {
paths?: Partial<Record<TreePathId, string>>;
spheres?: Partial<Record<TreeSphereId, string | string[]>>;
specialSphereMode?: "preserve" | "plain";
}
  • highlights.paths overrides only the main color of the specified path lines. The existing edge and highlight layers stay intact.
  • highlights.spheres overrides only the specified sphere fills. Unmentioned spheres keep their normal renderer output.
  • highlights.specialSphereMode controls only highlighted special spheres. It defaults to "preserve", so highlighted Kether, Chokhmah, Daath, and Malkuth keep their special renderer structure unless you opt into "plain".
  • Arrays are mainly useful for multi-fill spheres like Malkuth; a single string works for ordinary sphere tinting.
import { generateTreeSvg } from 'kaabalah/visual';
import { id, KaabalahTypes } from 'kaabalah/core';
const svg = generateTreeSvg({
background: "#fff",
highlights: {
paths: {
[id(KaabalahTypes.PATH, "1")]: "#d97706",
},
spheres: {
[id(KaabalahTypes.SPHERE, "Kether")]: "#fde68a",
[id(KaabalahTypes.SPHERE, "Malkuth")]: [
"#facc15",
"#f59e0b",
"#b45309",
"#fef3c7",
],
},
},
});

This is the intended downstream contract for apps: request selective recolors from kaabalah-lib instead of masking or rebuilding the SVG app-side.

When you want to mute every non-selected node to a single neutral color while keeping selected special spheres canonical, set highlights.specialSphereMode: "plain" and leave the selected nodes unmentioned:

import { generateTreeSvg, TREE_PATH_IDS, TREE_SPHERE_IDS } from 'kaabalah/visual';
import { id, KaabalahTypes } from 'kaabalah/core';
const muted = "#aaa";
const selectedPathId = id(KaabalahTypes.PATH, "1");
const selectedSphereIds = [
id(KaabalahTypes.SPHERE, "Kether"),
id(KaabalahTypes.SPHERE, "Chokhmah"),
];
const svg = generateTreeSvg({
background: "#fff",
highlights: {
specialSphereMode: "plain",
paths: Object.fromEntries(
TREE_PATH_IDS
.filter((pathId) => pathId !== selectedPathId)
.map((pathId) => [pathId, muted])
),
spheres: Object.fromEntries(
TREE_SPHERE_IDS
.filter((sphereId) => !selectedSphereIds.includes(sphereId))
.map((sphereId) => [sphereId, muted])
),
},
});

Daath Layer

By default (daathLayer: "front"), Daath renders in the normal front sphere layer above all paths. Setting daathLayer: "back" moves Daath behind the paths — useful when you want paths to visually cross over Daath. A transparent hit-area circle (pointer-events="all", data-node-id="sphere:Daath") is placed last in the SVG so interactive clicks on Daath still work.

const svg = generateTreeSvg({ daathLayer: "back" });

Daath layer comparison

Daath in front (default)
daathLayer=“front” (default)
Daath behind paths
daathLayer=“back”

getTreeRenderModel(options?)

Returns the canonical layout together with activation-aware geometry and metadata for every sphere and path. Use this when an app needs stable tooltip anchors, hit targets, or prominence information without rebuilding the tree math locally.

function getTreeRenderModel(options?: TreeSvgOptions): TreeRenderModel

The model includes:

  • canonical viewBox and rendered scale
  • layer order
  • sphere and path geometry in both percentage space and viewBox units
  • tooltip anchors
  • invisible hit target geometry in the same viewBox coordinate system as the base SVG
  • canonical color and material metadata
  • activation state with normalized strength

This is the intended downstream contract for interactive tree surfaces that need to place their own overlays or tooltips. Use geometry.viewBoxUnits for SVG rings, hit targets, and path strokes so circles stay circular. Use geometry.percentages.anchor when you need CSS-positioned HTML tooltips above the map.

Activation usage with semantic map data

kaabalah/semantic owns the marker and correspondence rules. kaabalah/visual owns the target geometry and activation rendering.

import { buildKaabalisticMapData } from 'kaabalah/semantic';
import { generateTreeSvg, getTreeRenderModel } from 'kaabalah/visual';
const mapData = buildKaabalisticMapData({
numerology: new Date("1990-01-01T12:00:00Z"),
});
const targets = [
...mapData.spheres.map((sphere) => ({ id: sphere.id, type: "sphere" as const })),
...mapData.paths.map((path) => ({ id: path.id, type: "path" as const })),
];
const maxCount = Math.max(
1,
...targets.map((target) => mapData.countsById[target.id]?.total ?? 0)
);
const activations = targets.map((target) => {
const count = mapData.countsById[target.id]?.total ?? 0;
return {
targetId: target.id,
targetType: target.type,
count,
total: mapData.markers.length,
strength: count / maxCount,
state: count > 0 ? "active" as const : "inactive" as const,
};
});
const svg = generateTreeSvg({
background: "transparent",
activations,
});
const model = getTreeRenderModel({ activations });

getTreeLayout(system?)

Returns the canonical layout data for the Tree of Life without rendering any SVG. Use this to build custom renderers, overlays, or interactive diagrams.

function getTreeLayout(system?: SystemKey): TreeLayout

system defaults to "kaabalah". Valid values: "kaabalah", "hermetic-qabalah", "lurianic-kabbalah".

TreeLayout

interface TreeLayout {
system: SystemKey;
viewBox: Required<TreeSvgViewBox>; // { minX, minY, width, height }
sphereOrder: TreeSphereId[]; // 11 sphere IDs in draw order
pathOrder: TreePathId[]; // 22 path IDs in draw order
percentages: TreeLayoutMap; // coordinates as 0–100 percentages
viewBoxUnits: TreeLayoutMap; // coordinates in viewBox pixel units
}
interface TreeLayoutMap {
spheres: Record<TreeSphereId, TreeLayoutCoordinate>;
paths: Record<TreePathId, TreeLayoutPath>;
}
interface TreeLayoutCoordinate {
x: number;
y: number;
}
interface TreeLayoutPath {
fromId: TreeSphereId;
toId: TreeSphereId;
from: TreeLayoutCoordinate;
to: TreeLayoutCoordinate;
}

percentages gives coordinates as percentages of the viewBox dimensions (0–100), making them resolution-independent. viewBoxUnits gives the same coordinates already scaled to the default 286 × 561 viewBox.

Example

import { getTreeLayout, TREE_SVG_DEFAULT_VIEWBOX } from 'kaabalah/visual';
import { id, KaabalahTypes } from 'kaabalah/core';
const layout = getTreeLayout();
// Kether sits at roughly the top-center of the canvas
layout.percentages.spheres[id(KaabalahTypes.SPHERE, "Kether")];
// { x: 49.94, y: 6.83 }
layout.viewBoxUnits.spheres[id(KaabalahTypes.SPHERE, "Kether")];
// { x: 142.83, y: 38.32 }
// Path 1 connects Kether to Chokhmah
layout.percentages.paths[id(KaabalahTypes.PATH, "1")];
// { fromId: "sphere:Kether", toId: "sphere:Chokhmah",
// from: { x: 49.94, y: 6.83 }, to: { x: 86.66, y: 17.68 } }
// Scale to a custom canvas
const canvasWidth = 600;
const canvasHeight = 1175;
const ketherX = layout.percentages.spheres[id(KaabalahTypes.SPHERE, "Kether")].x / 100 * canvasWidth;

Constants

TREE_SVG_DEFAULT_VIEWBOX

The canonical viewBox for all SVG output:

const TREE_SVG_DEFAULT_VIEWBOX: Required<TreeSvgViewBox> = {
minX: 0,
minY: 0,
width: 286,
height: 561,
};

TREE_SPHERE_NAMES

A readonly tuple of all 11 sphere names in draw order:

const TREE_SPHERE_NAMES = [
"Kether", "Chokhmah", "Binah", "Daath",
"Chesed", "Geburah", "Tiphareth",
"Netzach", "Hod", "Yesod", "Malkuth",
] as const;

TREE_SPHERE_IDS

Sphere node IDs corresponding to TREE_SPHERE_NAMES, in the same order. Each ID has the form "sphere:<Name>".

TREE_SPHERE_IDS[0] // "sphere:Kether"
TREE_SPHERE_IDS[6] // "sphere:Tiphareth"

TREE_PATH_IDS

Path node IDs for paths 1–22 in ascending order. Each ID has the form "path:<N>".

TREE_PATH_IDS[0] // "path:1"
TREE_PATH_IDS[21] // "path:22"

CLI

The CLI can render both visual modules directly.

Astrology wheel

Use astrology:wheel to calculate a chart and pass it through generateAstroWheelSvg:

Terminal window
# Emit a compact JSON payload containing only the SVG
kaabalah astrology:wheel 1990-01-15 14:30 --lat=40.7128 --lon=-74.006 --json --compact --fields=svg
# Write the SVG to disk
kaabalah astrology:wheel 1990-01-15 14:30 --lat=40.7128 --lon=-74.006 --background=transparent --output=chart.svg --json
# Inspect the geometry used by the SVG renderer
kaabalah astrology:wheel 1990-01-15 14:30 --lat=40.7128 --lon=-74.006 --render-model --json --compact

Pass advanced visual options through --input-json as wheelOptions:

Terminal window
kaabalah astrology:wheel --input-json='{"date":"1990-01-15","time":"14:30","lat":40.7128,"lon":-74.006,"wheelOptions":{"background":"transparent","aspects":false}}' --json --compact --fields=svg

Tree of Life

The existing tree:* CLI namespace can inspect the same visual contracts:

Terminal window
# Generate an SVG file
kaabalah tree:svg --background=transparent --output=tree.svg --json
# Preview an activated SVG from a reusable activation payload
kaabalah tree:svg --background=transparent --activations=activations.json --json --compact --fields=svg
# Inspect anchors and hit targets for agents or custom renderers
kaabalah tree:layout --render-model --activations=activations.json --json --compact

--activations accepts either a raw JSON array of TreeTargetActivationInput objects or an object with an activations array. Keep semantic marker creation in kaabalah/semantic; use the CLI activation payload only as a visual inspection format.