DEV Community

Cover image for I Built a Free Astrocartography Calculator with Next.js — Here's the Full Story
冠

Posted on

I Built a Free Astrocartography Calculator with Next.js — Here's the Full Story

Most astrocartography tools online are either locked behind a $20/month paywall, built on Flash-era technology, or so cluttered with ads you can barely find the actual calculator. As a developer who stumbled into the world of astrology charts, I kept thinking: someone should just build a clean, free one.

So I did. Here's the honest story of how I built Astrocarto — the technical decisions, the unexpected hard parts, and what I'd do differently.

What Even Is Astrocartography?

Quick background for the non-astrology crowd (which is probably most of you):

Astrocartography is a technique that takes the positions of planets at the exact moment you were born and projects them as lines onto a world map. The idea is that certain locations carry specific planetary energies for you — your "Venus line" might run through Paris, your "Mars line" through somewhere you'd rather avoid.

Whether or not you believe any of that — the math is genuinely fascinating. We're talking about:

  • Calculating precise planetary positions using historical ephemeris data
  • Transforming between multiple astronomical coordinate systems
  • Projecting those coordinates onto a 2D geographic map

As a developer, I was hooked on the problem before I even thought about the product.


The Tech Stack

Framework:        Next.js 14 (App Router)
Styling:          Tailwind CSS
Map Rendering:    Leaflet + React-Leaflet
Astro Calc:       astronomia (npm)
Deployment:       Vercel
Enter fullscreen mode Exit fullscreen mode

I'll explain the key choices below.


Why Next.js?

Three reasons:

1. SEO is everything for a niche tool

People actively search for "free astrocartography calculator" — I needed server-side rendering so those pages could rank. With Next.js App Router, my calculator pages are fully rendered on the server before they hit the browser.

2. Route Handlers for calculation logic

I didn't want heavy astronomical math running on the client. Next.js Route Handlers let me keep that on the server cleanly:

// app/api/calculate/route.js
export const runtime = 'nodejs'; // critical — don't use Edge here

export async function POST(request) {
  const { birthDate, birthTime, lat, lng } = await request.json();

  const chart = calculateNatalChart({ birthDate, birthTime, lat, lng });

  return Response.json({ chart });
}
Enter fullscreen mode Exit fullscreen mode

3. Zero-config Vercel deployment

Push to main → live in 30 seconds. For an indie project, this matters.


The Hardest Part: Astronomical Calculations

I expected the map to be the hard part. I was wrong. The calculations nearly broke me.

Using the astronomia library

astronomia is a JavaScript port of Jean Meeus's Astronomical Algorithms — the gold standard reference for this kind of math. It handles the heavy lifting of planetary position calculations.

Here's a simplified version of how I get a planet's ecliptic longitude:

import { solar, julian, base } from 'astronomia';

function getPlanetPosition(birthDate, birthTime) {
  // Convert birth datetime to Julian Day Number
  const dateStr = `${birthDate}T${birthTime}:00Z`;
  const jd = julian.DateToJD(new Date(dateStr));

  // Get Sun's position (as example)
  const sunPos = solar.apparentLongitude(jd);

  // Convert from radians to degrees
  const longitude = base.pmod(sunPos * 180 / Math.PI, 360);

  return longitude;
}
Enter fullscreen mode Exit fullscreen mode

The coordinate system nightmare

Where it got painful: astrocartography lines require converting between three coordinate systems:

  1. Ecliptic coordinates — where planets are relative to Earth's orbital plane
  2. Equatorial coordinates — right ascension + declination (like lat/lng for space)
  3. Geographic coordinates — actual latitude/longitude on Earth's surface

For each planet, I need to find every latitude on Earth where that planet was on the Ascendant, Descendant, Midheaven, or IC at the moment of birth. That means iterating through latitudes and solving for the longitude where the condition holds.

function findAscendantLine(planet, jd) {
  const points = [];

  // Step through every latitude
  for (let lat = -80; lat <= 80; lat += 0.5) {
    // Binary search for the longitude where this planet rises
    const lng = solveForAscendant(planet, jd, lat);
    if (lng !== null) {
      points.push([lat, lng]);
    }
  }

  return points;
}
Enter fullscreen mode Exit fullscreen mode

Getting this right took me about two weeks of head-scratching, cross-referencing with known charts, and fixing edge cases near the poles.


Rendering the Map with Leaflet

Once I had the coordinate arrays, rendering them with Leaflet was comparatively straightforward:

import { MapContainer, TileLayer, Polyline } from 'react-leaflet';

export function AstroMap({ planetLines }) {
  return (
    <MapContainer
      center={[20, 0]}
      zoom={2}
      style={{ height: '600px', width: '100%' }}
    >
      <TileLayer
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        attribution="© OpenStreetMap contributors"
      />

      {planetLines.map(({ planet, points, color }) => (
        <Polyline
          key={planet}
          positions={points}
          pathOptions={{ color, weight: 2, opacity: 0.8 }}
        />
      ))}
    </MapContainer>
  );
}
Enter fullscreen mode Exit fullscreen mode

One Leaflet gotcha with Next.js: Leaflet touches window on import, which breaks SSR. Fix:

// Use dynamic import with ssr: false
const AstroMap = dynamic(() => import('@/components/AstroMap'), {
  ssr: false,
  loading: () => <div className="map-skeleton" />
});
Enter fullscreen mode Exit fullscreen mode

What Astrocarto Can Do Right Now

The tool currently supports:

  • Rising Sign Calculator — your ascendant based on exact birth time + location
  • Natal Chart — full planetary positions at birth
  • Transit Chart — current planetary positions overlaid on your natal chart
  • Relocation Chart — how your chart shifts if you move cities

All free. No account required. Just enter your birth details and go.

Try it: astrocarto.org


What I'd Do Differently

1. Validate calculations against existing tools first

I spent days debugging math that turned out to be correct — I just didn't have a reliable reference to check against. Next time I'd set up automated comparison tests against established chart software from day one.

2. Build the map UI before perfecting the calculations

Seeing lines on a map, even approximate ones, keeps you motivated. I got too deep into calculation accuracy before I had anything visual to show for it.

3. Add caching earlier

Astronomical calculations for the same birth data always return the same result. I should have added a simple cache from the start rather than recalculating on every request.

// Simple in-memory cache I added later
const cache = new Map();

export async function POST(request) {
  const body = await request.json();
  const cacheKey = JSON.stringify(body);

  if (cache.has(cacheKey)) {
    return Response.json(cache.get(cacheKey));
  }

  const result = calculateNatalChart(body);
  cache.set(cacheKey, result);

  return Response.json(result);
}
Enter fullscreen mode Exit fullscreen mode

What's Next

  • [ ] Mobile-optimized map gestures
  • [ ] Shareable chart URLs (so you can send your chart to a friend)
  • [ ] PDF export
  • [ ] More celestial bodies — asteroids, Chiron, nodes

Building niche tools is genuinely one of my favorite things to do as an indie developer. The intersection of an obscure domain and a real technical problem is where the most interesting projects live.

If you've built something in a weird niche — astrology, birdwatching, chess, anything — I'd love to hear about it in the comments.

And if you're curious about your own astrocartography: astrocarto.org — takes about 60 seconds.

Top comments (1)

Collapse
 
_eb3468ba11d30aaf81a0e85 profile image

Just published this after sitting on the draft for a while — the coordinate system conversion was genuinely the most humbling part of this whole project 😅

If you've ever tried to mix astronomical math with web dev, I'd love to compare notes. And if you give astrocarto.org a try, let me know what you think — always looking for feedback from fresh eyes.