A modern, extensible Python library for computational astrology
Built on Swiss Ephemeris for NASA-grade astronomical accuracy, Stellium brings professional astrological calculations to Python with a clean, composable architecture that works for everyone, from quick scripts to production applications.
Read the extensive documentation and API autodocs at Read The Docs.
Try out some quick examples immediately, no installation needed:
β¨ Stellium The Webapp is live! Visit it here! β¨
Star the repo if you find it useful! β
- Fully typed with modern type hints for excellent IDE support
- Protocol-driven architecture - extend with custom engines, no inheritance required
- Fluent builder pattern - chainable, readable, intuitive API
- Flexible input formats - accepts datetime strings, city names, or precise coordinates
- Modular & composable - mix and match components as needed
- Production-ready with comprehensive test coverage
Western:
- Large-scale data analysis with pandas DataFrames, batch calculation, and statistical tools
- 23+ house systems including Placidus, Whole Sign, Koch, Equal, Regiomontanus, and more (see the full list)
- Declination calculations with out-of-bounds planet detection and parallel/contraparallel aspects
- Bi-wheel charts for synastry, transits, progressions, returns, arc directions, and composite analysis
- Sect-aware calculations with proper day/night chart handling
- 25+ Arabic Parts with traditional formulas (see the full list)
- Essential & accidental dignity scoring for both traditional and modern rulerships
- Chart rulership and profections for traditional astrology
- Dispositor graphs for planets and (experimentally) houses in reports
- Aspect pattern detection - Grand Trines, T-Squares, Yods, Stelliums, and more
- Zodiacal Releasing for 25+ lots (including Fortune and Spirit) and optional "fractal" calculation mode
- Uranian astrology including Trans-Neptunian Planets and 45/90/360-degree dials with pointers.
- Primary and Zodiacal directions with 3D modeling and and distribution across bounds
- Draconic Charts and Void of Course Moon
- Electional astrology - Find auspicious times with 30+ predicates, interval optimization, and planetary hours
- Heliocentric positions
- Antiscia and contra-antiscia with a dedicated report section
- Beautiful visualizations with professional SVG chart rendering and 13 themes
- Beautiful Composable PDF or CLI reports to show nitty-gritty details of the chart (see this example for a subset of what's available)
- Notable births database for quick exploration and learning. Check out the current list
Vedic:
- Both tropical and sidereal zodiacs with 9 ayanamsa systems for Vedic astrology
Chinese:
- [WIP] Ba Zi system with Ten Gods and Hidden Stems
Unlike other Python astrology libraries, Stellium is designed for extensibility:
# Other libraries: rigid, hard-coded calculations
chart = AstrologyLibrary(date, location) # That's all you can do
# Stellium: composable, configurable, extensible
chart = (ChartBuilder.from_details("2000-01-06 12:00", "Seattle, WA")
.with_house_systems([PlacidusHouses(), WholeSignHouses()]) # Multiple systems!
.with_sidereal("lahiri") # Sidereal zodiac option
.with_aspects(ModernAspectEngine()) # Swap aspect engines
.with_orbs(LuminariesOrbEngine()) # Custom orb rules
.add_component(ArabicPartsCalculator()) # Plugin-style components
.add_component(MidpointCalculator()) # Stack as many as you want
.calculate()) # Lazy evaluation- Performance - Advanced caching system makes repeated calculations fast
- Flexibility - Calculate multiple house systems simultaneously
- Accuracy - Swiss Ephemeris provides planetary positions accurate to fractions of an arc-second
- Modern Python - Takes full advantage of Python 3.11+ features
pip install stellium- Python 3.11 or higher
- All dependencies installed automatically (pyswisseph, pytz, geopy, rich, svgwrite)
# For data analysis with pandas DataFrames
pip install stellium[analysis]from stellium import ChartBuilder
chart = ChartBuilder.from_notable("Albert Einstein").calculate()
chart.draw("einstein.svg").save()That's it! You now have a beautiful natal chart SVG for Einstein.
The from_notable() factory method uses our curated database of famous births. Other notables include: "Carl Jung", "Frida Kahlo", "Marie Curie", and more. Check out the current list.
Want to customize your chart? The fluent .draw() API makes it effortless:
# Apply a preset for instant results
chart.draw("detailed.svg").preset_detailed().save()
# Choose a theme
chart.draw("midnight.svg").with_theme("midnight").save()
# Full customization
chart.draw("custom.svg") \
.with_theme("celestial") \
.with_zodiac_palette("rainbow_celestial") \
.with_moon_phase(position="bottom-left", show_label=True) \
.with_chart_info(position="top-left") \
.save()Discover features through autocomplete! Type chart.draw(). and your IDE will show you everything available.
π See the Visualization Guide for complete documentation, theme gallery, and examples.
from stellium import ChartBuilder
# Quick method: just pass datetime string and location
chart = ChartBuilder.from_details(
"2000-01-06 12:00", # ISO format, US format, or European format
"Seattle, WA" # City name or (lat, lon) tuple
).calculate()
# Access planetary positions
sun = chart.get_object("Sun")
print(sun)
moon = chart.get_object("Moon")
print(moon)
print(moon.phase)Sun: 0Β°0' Libra (180Β°)
Moon: 0Β°0' Aries (0Β°)
Phase: Full (100% illuminated)Key Features:
- Flexible datetime parsing: ISO 8601, US format, European format, or date-only
- Automatic geocoding: City name β coordinates
- Automatic timezone handling: Naive datetimes converted to UTC
- Smart defaults: Placidus houses, major (Ptolemaic) aspects, tropical zodiac
from stellium import ChartBuilder
# Modern convenience method - accepts datetime strings!
chart = ChartBuilder.from_details("2000-01-06 12:00", "Seattle, WA").calculate()
# Get all planets
for planet in chart.get_planets():
print(f"{planet.name}: {planet.longitude:.2f}Β° {planet.sign}")
# Get aspects
for aspect in chart.aspects:
print(f"{aspect.object1.name} {aspect.aspect_name} {aspect.object2.name} (orb: {aspect.orb:.2f}Β°)")
# Get house cusps
houses = chart.get_houses() # Returns HouseCusps for default (or first) system
for i, cusp in enumerate(houses.cusps, 1):
print(f"House {i}: {cusp:.2f}Β°")from stellium import ChartBuilder
from stellium.engines import WholeSignHouses, ModernAspectEngine, SimpleOrbEngine
chart = (ChartBuilder.from_details("2000-01-06 12:00", "Seattle, WA")
.with_house_systems([WholeSignHouses()]) # Use Whole Sign houses
.with_aspects(ModernAspectEngine()) # Explicit aspect engine
.with_orbs(SimpleOrbEngine()) # Simple orb rules
.calculate())
print(f"House System: {chart.default_house_system}")
# Access house cusps for the specific system
whole_sign_cusps = chart.get_house_cusps("Whole Sign")
print(whole_sign_cusps.get_description(1)) # First HouseAvailable House Systems: Placidus (default), Whole Sign, Koch, Equal, Regiomontanus, Campanus, Porphyry, Alcabitius, Equal (MC), Vehlow Equal, Topocentric, Morinus, and 11+ more.
from stellium import ChartBuilder
from stellium.engines import PlacidusHouses, WholeSignHouses, KochHouses
chart = (ChartBuilder.from_details("2000-01-06 12:00", "Seattle, WA")
.with_house_systems([
PlacidusHouses(),
WholeSignHouses(),
KochHouses()
])
.calculate())
# Access each system independently
sun = chart.get_object("Sun")
print(f"Sun in Placidus House: {sun.house}")
# House placements are tracked per-system
sun_ws_house = sun.house_placements.get("Whole Sign")
print(f"Sun in Whole Sign House: {sun_ws_house}")
sun_koch_house = sun.house_placements.get("Koch")
print(f"Sun in Koch House: {sun_koch_house}")from stellium import ChartBuilder
from stellium.components import ArabicPartsCalculator, MidpointCalculator
chart = (ChartBuilder.from_details("2000-01-06 12:00", "Seattle, WA")
.add_component(ArabicPartsCalculator())
.add_component(MidpointCalculator())
.calculate())
# Arabic Parts (automatically sect-aware)
arabic_parts = chart.get_component_result("Arabic Parts")
for part in arabic_parts:
print(f"{part.name:25} {part.longitude:6.2f}Β° {part.sign:12} House {part.house}")
# Midpoints
midpoints = chart.get_component_result("Midpoints")
for mp in midpoints[:5]: # First 5 midpoints
print(f"{mp.object1.name}/{mp.object2.name} midpoint: {mp.longitude:.2f}Β°")Available Components:
ArabicPartsCalculator- 25+ traditional lots (Part of Fortune, Spirit, Love, etc.)MidpointCalculator- Direct midpoints for all planet pairsDignityComponent- Essential dignities (rulership, exaltation, triplicity, etc.)AspectPatternAnalyzer- Detect Grand Trines, T-Squares, Yods, Stelliums, etc.
from stellium import ChartBuilder, Native, ReportBuilder
from stellium.components import DignityComponent, AspectPatternAnalyzer
from datetime import datetime
native = Native(datetime(2000, 1, 6, 12, 00), "Seattle, WA")
chart = (ChartBuilder.from_native(native)
.add_component(DignityComponent())
.add_component(AspectPatternAnalyzer())
.calculate())
# Build a comprehensive terminal report
report = (ReportBuilder()
.from_chart(chart)
.with_chart_overview() # Chart metadata (date, location, zodiac system)
.with_planet_positions(house_systems="all") # Positions with ALL house systems
.with_declinations() # Declination table with OOB detection
.with_house_cusps(systems="all") # House cusps for all systems
.with_aspects(mode="major") # Major aspects table
.with_aspect_patterns() # Grand Trines, T-Squares, Yods, etc.
.with_dignities(essential="both")) # Essential dignities (traditional + modern)
report.render(format="rich_table") # Beautiful terminal output
# Export to file
report.render(format="plain_table", file="my_chart.txt")
report.render(format="pdf", file="my_chart.pdf") # PDF with Typstfrom stellium import ComparisonBuilder
# Synastry chart (relationship analysis)
synastry = ComparisonBuilder.synastry(
("1994-01-06 11:47", "Palo Alto, CA", "Kate"),
("1995-06-15 14:30", "Seattle, WA", "Alex")
).calculate()
# Draw bi-wheel with both charts
synastry.draw("synastry_biwheel.svg") \
.preset_detailed() \
.save()
# Access inner and outer charts separately
inner_chart = synastry.inner_chart
outer_chart = synastry.outer_chart
# Get aspects between the two charts
interaspects = synastry.interaspects
for aspect in interaspects[:10]:
print(f"{aspect.object1.name} ({inner_chart.name}) "
f"{aspect.aspect_name} "
f"{aspect.object2.name} ({outer_chart.name})")Comparison Chart Types:
- Synastry: Relationship compatibility and dynamics
- Transit: Current planetary influences on natal chart
- Progression: Secondary progressions for timing
- Composite: Relationship midpoint chart (synthesis)
- Davison: Relationship chart with actual location
Stellium includes a CLI for quick chart generation:
# Generate a chart from the notable database
stellium chart notable "Albert Einstein" --output einstein.svg
# Manage ephemeris data
stellium ephemeris download --years 1000-3000
# Clear calculation cache
stellium cache clearSee stellium --help for full CLI documentation.
- Tropical Zodiac (Western astrology) - default
- Sidereal Zodiac (Vedic/Hindu astrology) with 9 ayanamsa systems:
- Lahiri (default for sidereal)
- Fagan-Bradley
- Raman
- Krishnamurti
- Yukteshwar
- J.N. Bhasin
- True Chitrapaksha
- True Revati
- De Luce
# Tropical (default)
chart = ChartBuilder.from_native(native).calculate()
# Sidereal with Lahiri ayanamsa
chart = ChartBuilder.from_native(native).with_sidereal("lahiri").calculate()
# Sidereal with custom ayanamsa
chart = ChartBuilder.from_native(native).with_sidereal("fagan_bradley").calculate()Calculate positions for 50+ celestial objects:
- Planets: Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto
- Asteroids: Chiron, Ceres, Pallas, Juno, Vesta
- Lunar Nodes: North Node, South Node, True Node, Mean Node
- Lunar Apogee: Lilith (Mean, True, Osculating, Interpolated)
- Chart Points: Ascendant, Midheaven, Descendant, IC, Vertex, East Point
- Ecliptic Coordinates: Longitude, latitude (distance from ecliptic)
- Equatorial Coordinates: Right ascension, declination (distance from celestial equator)
- Out-of-Bounds Detection: Automatically identifies planets with extreme declinations (>23Β°27')
sun = chart.get_object("Sun")
print(f"Ecliptic: {sun.longitude:.2f}Β° longitude, {sun.latitude:.2f}Β° latitude")
print(f"Equatorial: {sun.right_ascension:.2f}Β° RA, {sun.declination:.2f}Β° declination")
if sun.is_out_of_bounds:
print(f"β Sun is out of bounds!")- Major Aspects (Ptolemaic): Conjunction (0Β°), Opposition (180Β°), Square (90Β°), Trine (120Β°), Sextile (60Β°)
- Minor Aspects: Semi-sextile (30Β°), Semi-square (45Β°), Sesquiquadrate (135Β°), Quincunx (150Β°)
- Harmonic Aspects: Quintile (72Β°), Bi-quintile (144Β°), Septile (51.43Β°), Novile (40Β°), and more
- Configurable Orbs: Simple, Luminaries-specific, or Complex (aspect-and-planet-pair-specific) orb engines
- Essential Dignities: Ruler, Exaltation, Triplicity (by sect), Bound, Decan, Detriment, Fall
- Accidental Dignities: House placement, angular/succedent/cadent, joy
- Both Traditional & Modern rulerships supported
Create relationship, timing, and synthesis charts:
from stellium import ComparisonBuilder
# Synastry (relationship analysis)
synastry = ComparisonBuilder.synastry(
("1994-01-06 11:47", "Palo Alto, CA", "Person A"),
("1995-06-15 14:30", "Seattle, WA", "Person B")
).calculate()
synastry.draw("synastry.svg").save()
# Transits (timing analysis)
transits = ComparisonBuilder.transit(
natal_data=("1994-01-06 11:47", "Palo Alto, CA"),
transit_data=("2025-11-26 12:00", "Palo Alto, CA")
).calculate()
# Composite (relationship midpoint chart)
composite = ComparisonBuilder.composite(
("1994-01-06 11:47", "Palo Alto, CA"),
("1995-06-15 14:30", "Seattle, WA")
).calculate()
# Davison (relationship midpoint chart with actual location)
davison = ComparisonBuilder.davison(
("1994-01-06 11:47", "Palo Alto, CA"),
("1995-06-15 14:30", "Seattle, WA")
).calculate()Comparison Types:
- Synastry: Two natal charts overlaid (bi-wheel)
- Transit: Natal chart + current/future planets
- Progression: Natal chart + progressed positions
- Composite: Midpoint chart (mathematical average)
- Davison: Midpoint chart with actual geographic location
Handle charts when birth time is unknown:
# Create chart with unknown time (defaults to noon, skips houses/angles)
chart = ChartBuilder.from_details(
"1994-01-06", # Date only
"Palo Alto, CA",
time_unknown=True
).calculate()
# Visualize with Moon's daily arc
chart.draw("unknown_time.svg").save() # Shows Moon's possible range# Export to dictionary for JSON serialization
data = chart.to_dict()
# Includes:
# - All planetary positions with coordinates
# - House cusps for all calculated systems
# - All aspects with orbs
# - Component results (Arabic Parts, midpoints, etc.)
# - Chart metadata (date, location, timezone)Generate beautiful personalized astrological planners as PDF files:
from stellium import Native, PlannerBuilder
native = Native("1990-05-15 14:30", "San Francisco, CA")
planner = (
PlannerBuilder.for_native(native)
.year(2025)
.timezone("America/Los_Angeles")
.with_natal_chart()
.with_solar_return()
.with_graphic_ephemeris(harmonic=90)
.include_natal_transits() # All planets + Node + Chiron
.include_moon_phases()
.include_voc(mode="traditional")
.generate("my_planner.pdf")
)Planner Features:
- Front matter pages: Natal chart, progressed chart, solar return, annual profection, graphic ephemeris
- Monthly calendar grids: Full-page calendar view with all events displayed
- Weekly detail pages: 7-day spreads with compact event listings
- Daily events: Transit-to-natal aspects, Moon phases, VOC periods, ingresses, stations, eclipses
- Configurable: Week start (Sunday/Monday), page size (A4/Letter), binding margins
Requires: pip install typst
See the planner cookbook for detailed recipes.
Generate multi-page PDF documents with one chart per page, like an old-school astrologer's chart atlas:
from stellium.visualization.atlas import AtlasBuilder
# Create an atlas from notables
(AtlasBuilder()
.add_notable("Albert Einstein")
.add_notable("Marie Curie")
.add_notable("Isaac Newton")
.with_title_page("Famous Scientists")
.with_header()
.with_theme("midnight")
.save("scientists_atlas.pdf"))
# Or with Uranian dials
(AtlasBuilder()
.add_natives([native1, native2, native3])
.with_chart_type("dial", degrees=90)
.save("uranian_atlas.pdf"))
# Generate atlas from entire notables database
AtlasBuilder.from_all_notables().save("complete_atlas.pdf")
# Filter by category and sort by birth date
AtlasBuilder.from_all_notables(category="scientist", sort_by="date").save("scientists.pdf")Atlas Features:
- Multiple input methods: Add natives directly, look up notables by name, or use
from_all_notables()for the entire database - Category filtering: Filter notables by category (scientist, artist, etc.) and sort by name or date
- Chart types: Natal wheels or Uranian dials (90Β°, 45Β°, 360Β°)
- Configurable: Headers, themes, page sizes (Letter, A4, half-letter)
- Title page: Optional title page for the atlas
Requires: pip install typst
Batch calculate charts and analyze with pandas DataFrames:
from stellium.analysis import BatchCalculator, ChartStats, charts_to_dataframe
# Calculate 100s of charts from the notables database
charts = BatchCalculator.from_registry(category="scientist").calculate_all()
# Convert to pandas DataFrame
df = charts_to_dataframe(charts)
print(df['sun_sign'].value_counts())
# Statistical analysis
stats = ChartStats(charts)
print(stats.element_distribution())
print(stats.sign_distribution("Sun"))Requires: pip install stellium[analysis]
See the analysis cookbook for comprehensive examples.
from stellium.utils.cache import enable_cache, get_cache_stats
enable_cache(max_age_seconds=604800) # 1 week cache
# First calculation: ~200ms
chart1 = ChartBuilder.from_native(native).calculate()
# Subsequent calculations: ~10ms (20x faster!)
chart2 = ChartBuilder.from_native(native).calculate()
stats = get_cache_stats()
print(f"Cache hits: {stats['hits']}, misses: {stats['misses']}")The /examples directory contains comprehensive, runnable cookbooks:
| Cookbook | Description |
|---|---|
| chart_cookbook.py | 21 examples: themes, palettes, house systems, tables, and more |
| report_cookbook.py | 15 examples: terminal reports, PDF generation, batch processing |
| multichart_cookbook.py | Synastry, transits, bi-, tri- and quad-wheels, compatibility |
| returns_cookbook.py | 14 examples: returns (solar, lunar, planetary), relocations |
| progressions_cookbook.py | 15 examples: set by date, current date or age; various angle progression methods |
| arc_directions_cookbook.py | 14 examples: solar arc, naibod, lunar, chart ruler, sect, planetary arcs |
| profections_cookbook.py | 24 examples: annual, monthly profections for multiple points |
| zodiacal_releasing_cookbook.py | 14 examples: ZR timelines, snapshots, peaks, Loosing of Bond, reports |
| dial_cookbook.py | 16 examples: Uranian 90Β°/45Β°/360Β° dials, midpoints, pointers, transits, themes |
| ephemeris_cookbook.py | Examples of graphic ephemeris charts with optional natal overlays |
| electional_cookbook.py | 43 examples: finding auspicious times, predicates, planetary hours, aspect exactitude |
| planner_cookbook.py | 9 examples: PDF planners with charts, transits, Moon phases, VOC, calendar layouts |
| analysis_cookbook.ipynb | Jupyter notebook: batch calculation, pandas DataFrames, queries, statistics, export |
# Run any cookbook
python examples/chart_cookbook.py
python examples/report_cookbook.py
python examples/multichart_cookbook.py
python examples/returns_cookbook.py
python examples/progressions_cookbook.py
python examples/arc_directions_cookbook.py
python examples/profections_cookbook.py
python examples/zodiacal_releasing_cookbook.py
python examples/dial_cookbook.py
python examples/electional_cookbook.py
python examples/planner_cookbook.py| Guide | Description |
|---|---|
| VISUALIZATION.md | Complete chart drawing guide with fluent API reference |
| REPORTS.md | Report generation guide: sections, presets, PDF output |
| CHART_TYPES.md | Chart types: natal, synastry, transit, composite, Davison |
| Gallery | Description |
|---|---|
| THEME_GALLERY.md | Visual showcase of all 13+ chart themes |
| PALETTE_GALLERY.md | Zodiac ring color palettes with previews |
| HTML overview | Full color story overview of all themes and palettes |
| Document | Description |
|---|---|
| ARCHITECTURE.md | System architecture and design patterns |
| CONTRIBUTING.md | How to contribute (development setup) |
| CHANGELOG.md | Release history and version notes |
| PUBLISHING.md | Package publishing guide |
- See the full documentation list
# Clone and install
git clone https://github.com/katelouie/stellium.git
cd stellium
pip install -e .
# Run example cookbooks
python examples/chart_cookbook.py # Generate chart SVGs
python examples/report_cookbook.py # Generate PDF reports
python examples/comparison_cookbook.py # Generate synastry chartsStellium is built on three core principles:
Extend functionality by implementing protocols, not subclassing:
from stellium.core.protocols import ChartComponent
from typing import Protocol
class MyCustomComponent:
"""Add custom calculations without inheritance."""
@property
def component_name(self) -> str:
return "My Feature"
def calculate(self, chart_data, config):
# Your calculations here
return results
# Use it:
chart = ChartBuilder.from_native(native).add_component(MyCustomComponent()).calculate()Mix and match components freely:
# Every piece is optional and interchangeable
chart = (ChartBuilder.from_native(native)
.with_house_systems([PlacidusHouses(), WholeSignHouses()]) # Multiple systems
.with_aspects(ModernAspectEngine()) # Choose aspect engine
.with_orbs(LuminariesOrbEngine()) # Choose orb calculator
.add_component(ArabicPartsCalculator()) # Add components
.add_component(MidpointCalculator()) # Stack them up
.calculate())All calculation results are immutable dataclasses:
# Results are frozen - safe to cache and share
sun = chart.get_object("Sun")
sun.longitude = 100 # β Error: frozen dataclass
# This makes caching safe and reliable
cached_chart = chart # Safe to reuseBenefits:
- Thread-safe calculations
- Reliable caching
- No accidental mutations
- Easy to reason about
Stellium has comprehensive test coverage:
# Run all tests
pytest
# Run with coverage
pytest --cov=src --cov-report=term-missing
# Run specific test categories
pytest tests/test_chart_builder.py
pytest tests/test_integration.pySee TODO.md for the full development roadmap.
- β PDF Planner Generator - Create personalized astrological planners with charts, transits, Moon phases, and calendar layouts
- β Electional Astrology - Find auspicious times with 30+ predicates, interval optimization, and planetary hours
- β Data Analysis Module - Batch calculation, pandas DataFrames, queries, statistics
- β Sidereal Zodiac Support - 9 ayanamsa systems (Lahiri, Fagan-Bradley, Raman, etc.)
- β Declination Calculations - Out-of-bounds detection, equatorial coordinates
- β Bi-Wheel Charts - Synastry, transits, progressions, composite charts
- β Enhanced Reports - Dignities, aspect patterns, house cusps, declinations
- β Unknown Time Charts - Moon arc visualization for charts without birth time
We welcome contributions from both Python developers and astrologers! Whether you want to:
- Add new calculation engines
- Improve documentation
- Fix bugs
- Add new features
- Share examples
Please see CONTRIBUTING.md for detailed guidelines.
Quick Start for Contributors:
git clone https://github.com/katelouie/stellium.git
cd stellium
pip install -e ".[dev]" # Install with dev dependencies
pre-commit install # Set up pre-commit hooks
pytest # Run testsStellium is released under the MIT License. See LICENSE for details.
Note on Swiss Ephemeris: This library uses the Swiss Ephemeris, which has its own licensing terms for commercial use. See the Swiss Ephemeris website for details.
- Swiss Ephemeris - Astronomical calculations of exceptional accuracy
- Astro.com - Ephemeris data and astrological resources
- PySwissEph - Python bindings for Swiss Ephemeris
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: katehlouie@gmail.com
Built with precision, designed for everyone β¨
Whether you're building a professional astrology application, researching astrological patterns, or learning computational astrology: Stellium provides the tools you need with a modern, extensible architecture.
