Building SkyMoment: A 4K Personalized Star Map Generator with Python, Skyfield and Astronomical Data
Source: Dev.to
The idea
Most “star map posters” online aren’t based on real sky data; they use approximations, fake constellations, or pre‑rendered visuals. I wanted something more accurate and scientific:
- Real positions of stars
- Real coordinate transforms
- Proper field of view
- Natural‑looking Milky Way
- Clean and minimal layout
…and turn it into a small automated product: enter a moment → get a PDF/PNG → done.
Tech stack overview
- Python – main rendering pipeline
- Skyfield – planetary ephemeris & star calculations
- Hipparcos catalog – star positions & magnitudes
- Astropy – coordinate transforms
- Matplotlib – final 4K rendering
- Django – backend & API
- Lemon Squeezy – payments + webhooks
- SMTP – email delivery of the final poster
The frontend is intentionally minimal; the “magic” happens in the rendering pipeline.
Astronomical calculations step‑by‑step
When a user enters a date, time, and location (lat/lon), the pipeline does:
- Convert local time to UTC – Skyfield requires accurate UTC timestamps.
- Load planetary ephemeris – using DE421 / DE422 depending on the build.
- Load Hipparcos star catalog – provides RA/Dec, magnitude, proper motion.
- Transform everything into the user’s sky coordinates – using
AstropyAltAz transforms based on the observer’s position. - Filter stars – only stars above a certain brightness threshold are rendered.
- Split bright/faint stars – bright stars use a stylized 8‑point marker; faint stars use simple dots.
- Render the Milky Way – a custom multi‑noise layer (low‑frequency shapes, medium cloud structure, smooth alpha falloff, suppression of “sand grain” artifacts). This part took the longest to tune.
- Render at 4000 × 4000 resolution – Matplotlib does a great job when used carefully.
Total render time: ~35–40 seconds on server hardware.
Rendering performance challenges
4K resolution + thousands of stars + Milky Way noise layers = heavy. Some optimizations:
- Pre‑load catalogs once per worker
- Reuse figure objects
- Avoid expensive Python loops
- Limit use of transparency
- Skip stars below a certain magnitude
- Cache static layers when possible
Even small changes can save 10–20 % time.
Backend architecture (Django)
SkyMoment uses a simple pipeline:
- User configures their moment – chooses date/time/location and sees a preview.
- User is redirected to Lemon Squeezy checkout.
- After payment, LS sends a webhook to Django – containing order ID, custom fields (title, location, datetime), and product variant.
- Django creates a generation job – status transitions:
pending→generating→ready. - A worker process runs the Python renderer.
- The final 4K poster is saved to disk.
- Django sends an email with a download link.
Important detail: the webhook responds immediately; rendering happens asynchronously to avoid LS timeouts.
Example of what the system produces
Reduced‑size preview of a generated poster (insert image URL if desired).
The 4K version includes:
- Precise star positions
- Constellation lines
- Minimal typography
- Custom title & subtitle
- Clean dark theme
What’s next
Roadmap items:
- Multiple poster templates
- Faster rendering (caching or partial reuse)
- More curated landing pages
- Detailed generation logs and analytics
If you want to try generating a star map for your own moment:
🔗
Happy to answer any technical questions about astronomical data, rendering, or backend architecture!