swisseph-wasm
Version:
High-precision Swiss Ephemeris WebAssembly library for astronomical calculations in JavaScript
628 lines (502 loc) โข 16.3 kB
Markdown
# SwissEph WebAssembly Library
A high-precision JavaScript wrapper for the Swiss Ephemeris WebAssembly module, providing professional-grade astronomical calculations for astrology, astronomy, and related applications.
## ๐ Features
- **๐ฏ High Precision**: Based on the renowned Swiss Ephemeris
- **โก WebAssembly Performance**: Fast calculations in browser and Node.js
- **๐ Cross-Platform**: Works in Node.js, browsers, Vue.js, React, and more
- **๐ฆ Zero Dependencies**: Self-contained with embedded WASM
- **๐ง Easy Integration**: Simple import, works with all modern bundlers
- **๐ Comprehensive API**: Full access to Swiss Ephemeris functions
- **๐ป Modern JavaScript**: ES6+ with async/await support
- **๐งช Well Tested**: 106 tests with 86% coverage
- **๐ Complete Documentation**: Extensive guides and examples
- **๐ข Professional Grade**: Suitable for commercial applications
- **๐ CDN Ready**: Available via jsdelivr CDN for quick prototyping
## ๐ Live Demo
**Try it now**: [Interactive SwissEph Demo](https://prolaxu.github.io/swisseph-wasm/examples/demo.html)
Experience all features including:
- ๐ Real-time planetary positions
- ๐ Birth chart calculations
- โ๏ธ Sidereal vs Tropical comparisons
- ๐ House system calculations
- ๐ Planetary aspects analysis
- ๐ง Interactive API explorer
- ๐ Visual astrological charts
## ๐ฆ Installation
### npm
```bash
npm install swisseph-wasm
```
### yarn
```bash
yarn add swisseph-wasm
```
### pnpm
```bash
pnpm add swisseph-wasm
```
### CDN (Browser)
```html
<script type="module">
import SwissEph from 'https://cdn.jsdelivr.net/gh/prolaxu/swisseph-wasm@main/src/swisseph.js';
// Your code here
</script>
```
## ๐ฆ What's Included
- **Core Library** (`src/swisseph.js`) - Main JavaScript wrapper
- **WebAssembly Module** (`wsam/`) - Compiled Swiss Ephemeris
- **Comprehensive Tests** (`tests/`) - 106 tests covering all functionality
- **Documentation** - Complete API reference and guides
- **Examples** - Practical usage examples and patterns
- **Quick Reference** - Handy developer reference
- **TypeScript Definitions** - Full type support
## ๐ Quick Start
> **๐ Want to see it in action first?** Try the [Interactive Demo](https://prolaxu.github.io/swisseph-wasm/examples/demo.html)
### Basic Usage
```javascript
import SwissEph from 'swisseph-wasm';
// Create and initialize
const swe = new SwissEph();
await swe.initSwissEph();
// Calculate planetary position
const jd = swe.julday(2023, 6, 15, 12.0); // June 15, 2023, 12:00 UTC
const sunPos = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
console.log(`Sun longitude: ${sunPos[0]}ยฐ`);
// Clean up
swe.close();
```
### Birth Chart Example
```javascript
import SwissEph from 'swisseph-wasm';
// You can also import the example calculator
// import { BirthChartCalculator } from 'swisseph-wasm/examples/birth-chart.js';
const calculator = new BirthChartCalculator();
const chart = await calculator.calculateBirthChart({
year: 1990, month: 5, day: 15,
hour: 14, minute: 30, timezone: -5,
latitude: 40.7128, longitude: -74.0060
});
console.log('Planetary Positions:');
Object.entries(chart.planets).forEach(([name, planet]) => {
console.log(`${planet.symbol} ${name}: ${planet.zodiacSign.formatted}`);
});
calculator.destroy();
```
## ๐ Cross-Platform Usage
SwissEph WebAssembly works seamlessly across different environments. Here are platform-specific setup instructions:
### Node.js
```javascript
import SwissEph from 'swisseph-wasm';
async function nodeExample() {
const swe = new SwissEph();
await swe.initSwissEph();
const jd = swe.julday(2023, 6, 15, 12.0);
const sunPos = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
console.log(`Sun longitude: ${sunPos[0].toFixed(2)}ยฐ`);
swe.close();
}
nodeExample().catch(console.error);
```
### Vite (Vue.js, React, etc.)
Add this configuration to your `vite.config.js`:
```javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' // or react, etc.
export default defineConfig({
plugins: [vue()],
server: {
fs: {
allow: ['..']
}
},
assetsInclude: ['**/*.wasm'],
optimizeDeps: {
exclude: ['swisseph-wasm']
}
})
```
### Vue.js Component
```vue
<script setup>
import SwissEph from 'swisseph-wasm';
import { onMounted, onUnmounted, ref } from 'vue';
const swe = ref(null);
const isInitialized = ref(false);
const result = ref('');
onMounted(async () => {
try {
swe.value = new SwissEph();
await swe.value.initSwissEph();
isInitialized.value = true;
} catch (error) {
console.error('Failed to initialize SwissEph:', error);
}
});
onUnmounted(() => {
if (swe.value) {
swe.value.close();
}
});
const calculate = () => {
if (!isInitialized.value) return;
const jd = swe.value.julday(2023, 6, 15, 12.0);
const sunPos = swe.value.calc_ut(jd, swe.value.SE_SUN, swe.value.SEFLG_SWIEPH);
result.value = `Sun: ${sunPos[0].toFixed(2)}ยฐ`;
};
</script>
<template>
<div>
<button @click="calculate" :disabled="!isInitialized">
Calculate Sun Position
</button>
<p>{{ result }}</p>
</div>
</template>
```
### React Component
```jsx
import React, { useState, useEffect } from 'react';
import SwissEph from 'swisseph-wasm';
function AstrologyCalculator() {
const [swe, setSwe] = useState(null);
const [isInitialized, setIsInitialized] = useState(false);
const [result, setResult] = useState('');
useEffect(() => {
const initSwissEph = async () => {
try {
const swissEph = new SwissEph();
await swissEph.initSwissEph();
setSwe(swissEph);
setIsInitialized(true);
} catch (error) {
console.error('Failed to initialize SwissEph:', error);
}
};
initSwissEph();
return () => {
if (swe) {
swe.close();
}
};
}, []);
const calculate = () => {
if (!isInitialized || !swe) return;
const jd = swe.julday(2023, 6, 15, 12.0);
const sunPos = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
setResult(`Sun: ${sunPos[0].toFixed(2)}ยฐ`);
};
return (
<div>
<button onClick={calculate} disabled={!isInitialized}>
Calculate Sun Position
</button>
<p>{result}</p>
</div>
);
}
export default AstrologyCalculator;
```
### Vanilla HTML + JavaScript
```html
<!DOCTYPE html>
<html>
<head>
<title>SwissEph Example</title>
</head>
<body>
<button id="calculate">Calculate Sun Position</button>
<div id="result"></div>
<script type="module">
import SwissEph from 'https://cdn.jsdelivr.net/gh/prolaxu/swisseph-wasm@main/src/swisseph.js';
let swe = null;
let isInitialized = false;
// Initialize SwissEph
(async () => {
try {
swe = new SwissEph();
await swe.initSwissEph();
isInitialized = true;
console.log('SwissEph initialized successfully');
} catch (error) {
console.error('Failed to initialize SwissEph:', error);
}
})();
// Calculate button handler
document.getElementById('calculate').addEventListener('click', () => {
if (!isInitialized || !swe) {
document.getElementById('result').textContent = 'SwissEph not initialized';
return;
}
const jd = swe.julday(2023, 6, 15, 12.0);
const sunPos = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
document.getElementById('result').textContent = `Sun: ${sunPos[0].toFixed(2)}ยฐ`;
});
// Cleanup on page unload
window.addEventListener('beforeunload', () => {
if (swe) {
swe.close();
}
});
</script>
</body>
</html>
```
### Webpack Configuration
If using Webpack, add this to your `webpack.config.js`:
```javascript
module.exports = {
// ... other config
experiments: {
asyncWebAssembly: true,
},
module: {
rules: [
{
test: /\.wasm$/,
type: 'webassembly/async',
},
],
},
};
```
## ๐ Documentation
| Document | Description |
|----------|-------------|
| [**DOCUMENTATION.md**](DOCUMENTATION.md) | Complete API reference and usage guide |
| [**QUICK_REFERENCE.md**](QUICK_REFERENCE.md) | Quick developer reference |
| [**examples/README.md**](examples/README.md) | Example usage patterns |
| [**tests/README.md**](tests/README.md) | Test suite documentation |
## ๐ฏ Core Capabilities
### Planetary Calculations
- All major planets (Sun through Pluto)
- Lunar nodes and apogee
- Major asteroids (Chiron, Ceres, Pallas, etc.)
- Uranian planets
- Fixed stars
### Coordinate Systems
- Tropical and sidereal positions
- Geocentric, heliocentric, topocentric
- Ecliptic and equatorial coordinates
- Multiple ayanamsa systems
### Time Functions
- Julian Day calculations
- Time zone conversions
- Sidereal time
- Delta T calculations
- Calendar conversions
### Advanced Features
- Eclipse calculations
- Rise/set/transit times
- House systems
- Aspect calculations
- Atmospheric refraction
- Coordinate transformations
## ๐งช Testing
The library includes a comprehensive test suite with 106 tests:
```bash
npm install
npm test # Run all tests
npm run test:coverage # Run with coverage report
npm run test:watch # Watch mode
```
**Test Coverage:**
- โ
106 tests passing
- โ
86.1% statement coverage
- โ
66.66% function coverage
- โ
All major functionality covered
## ๐ Project Structure
```
swiss-wasm/
โโโ src/
โ โโโ swisseph.js # Main library file
โโโ wsam/
โ โโโ swisseph.js # WebAssembly module
โ โโโ swisseph.wasm # WebAssembly binary
โโโ tests/
โ โโโ swisseph.test.js # Core functionality tests
โ โโโ swisseph-advanced.test.js # Advanced features tests
โ โโโ swisseph-integration.test.js # Integration tests
โ โโโ swisseph-constants.test.js # Constants validation
โ โโโ __mocks__/ # Mock implementations
โ โโโ README.md # Test documentation
โโโ examples/
โ โโโ basic-usage.js # Basic usage examples
โ โโโ birth-chart.js # Birth chart calculator
โ โโโ README.md # Examples documentation
โโโ DOCUMENTATION.md # Complete API reference
โโโ QUICK_REFERENCE.md # Quick developer guide
โโโ README.md # This file
```
## ๐ Browser Support
**Modern Browsers:**
- Chrome 61+
- Firefox 60+
- Safari 11+
- Edge 16+
**Requirements:**
- WebAssembly support
- ES6 modules support
- Async/await support
## ๐ง Troubleshooting
### Common Issues and Solutions
#### WASM Loading Errors in Vite/Vue.js
**Error**: `WebAssembly.instantiate(): expected magic word 00 61 73 6d, found 3c 21 64 6f`
**Solution**: Add Vite configuration to your `vite.config.js`:
```javascript
export default defineConfig({
plugins: [vue()],
server: {
fs: { allow: ['..'] }
},
assetsInclude: ['**/*.wasm'],
optimizeDeps: {
exclude: ['swisseph-wasm']
}
})
```
#### Import Errors in Node.js
**Error**: `Cannot read properties of undefined (reading 'ccall')`
**Solution**: Always call `await swe.initSwissEph()` before using any methods:
```javascript
const swe = new SwissEph();
await swe.initSwissEph(); // Required!
const jd = swe.julday(2023, 6, 15, 12.0);
```
#### Browser Process Errors
**Error**: `process is not defined` in browser
**Solution**: This is fixed in the latest version. Update to the latest version:
```bash
npm update swisseph-wasm
```
#### Memory Issues
**Error**: Out of memory or performance issues
**Solution**: Always call `swe.close()` when done:
```javascript
try {
const swe = new SwissEph();
await swe.initSwissEph();
// ... your calculations
} finally {
swe.close(); // Always clean up!
}
```
#### CDN Import Issues
**Error**: Module not found when using CDN
**Solution**: Use the correct CDN URL:
```javascript
// โ
Correct
import SwissEph from 'https://cdn.jsdelivr.net/gh/prolaxu/swisseph-wasm@main/src/swisseph.js';
// โ Incorrect
import SwissEph from 'https://cdn.jsdelivr.net/npm/swisseph-wasm';
```
#### TypeScript Errors
**Error**: Type definitions not found
**Solution**: Types are included in the package:
```typescript
import SwissEph from 'swisseph-wasm';
// Types are automatically available
```
### Performance Tips
1. **Reuse instances**: Create one SwissEph instance and reuse it for multiple calculations
2. **Batch calculations**: Calculate multiple planets in one session rather than creating new instances
3. **Memory management**: Always call `close()` when done
4. **Async initialization**: Use `await swe.initSwissEph()` only once per instance
## ๐ก Examples
> **๐ Interactive Examples**: Try all these examples and more in the [Live Demo](https://prolaxu.github.io/swisseph-wasm/examples/demo.html)
### Current Planetary Positions
```javascript
async function getCurrentPositions() {
const swe = new SwissEph();
await swe.initSwissEph();
const now = new Date();
const jd = swe.julday(
now.getUTCFullYear(),
now.getUTCMonth() + 1,
now.getUTCDate(),
now.getUTCHours() + now.getUTCMinutes() / 60
);
const planets = [swe.SE_SUN, swe.SE_MOON, swe.SE_MERCURY];
const positions = {};
for (const planet of planets) {
const pos = swe.calc_ut(jd, planet, swe.SEFLG_SWIEPH);
positions[swe.get_planet_name(planet)] = pos[0];
}
swe.close();
return positions;
}
```
### Sidereal vs Tropical
```javascript
async function compareSystems(year, month, day) {
const swe = new SwissEph();
await swe.initSwissEph();
const jd = swe.julday(year, month, day, 12);
// Tropical
const tropical = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH);
// Sidereal (Lahiri)
swe.set_sid_mode(swe.SE_SIDM_LAHIRI, 0, 0);
const sidereal = swe.calc_ut(jd, swe.SE_SUN, swe.SEFLG_SWIEPH | swe.SEFLG_SIDEREAL);
swe.close();
return {
tropical: tropical[0],
sidereal: sidereal[0],
difference: tropical[0] - sidereal[0]
};
}
```
## ๐ง Development
### Running Examples
```bash
# Basic usage examples
node examples/basic-usage.js
# Birth chart calculation
node examples/birth-chart.js
```
### Performance Tips
1. **Reuse instances** for multiple calculations
2. **Batch operations** in single sessions
3. **Always clean up** with `swe.close()`
4. **Validate inputs** before calculations
5. **Use appropriate flags** for your needs
### Error Handling
```javascript
async function safeCalculation() {
let swe = null;
try {
swe = new SwissEph();
await swe.initSwissEph();
// calculations here
return result;
} catch (error) {
console.error('Calculation failed:', error);
return null;
} finally {
if (swe) swe.close();
}
}
```
## ๐ License
This library is a wrapper around the Swiss Ephemeris, which is licensed under the GNU General Public License (GPL) for non-commercial use. For commercial use, a license from Astrodienst is required.
**Swiss Ephemeris License:**
- Non-commercial use: Free under GPL
- Commercial use: Requires license from [Astrodienst](https://www.astro.com/swisseph/)
## ๐ค Contributing
1. Fork the repository
2. Create a feature branch
3. Add tests for new functionality
4. Ensure all tests pass
5. Update documentation
6. Submit a pull request
## ๐ Support
- **Documentation**: Check the comprehensive docs in this repository
- **Examples**: Review the examples directory for usage patterns
- **Tests**: Look at test files for detailed usage examples
- **Issues**: File issues on the project repository
## ๐ Credits
- **Swiss Ephemeris**: Created by Astrodienst AG
- **WebAssembly Port**: Compiled for web use
- **JavaScript Wrapper**: Modern ES6+ interface
- **Test Suite**: Comprehensive validation
- **Documentation**: Complete developer guides
---
**Ready to calculate the cosmos? Start with the [Quick Reference](QUICK_REFERENCE.md) or dive into the [Complete Documentation](DOCUMENTATION.md)!** ๐