Building SkyMoment: A 4K Personalized Star Map Generator with Python, Skyfield and Real Astronomical Data
I recently shipped a small side project called SkyMoment — a generator that creates personalized 4K star map posters using real astronomical data.
You enter a date, time, and location.
SkyMoment recreates the exact night sky for that moment and renders it as a minimalist, print-ready 4000×4000 poster.
🔗 Live demo: https://skymoment.art/
This post is a breakdown of how the system works — from astronomical calculations to rendering and backend automation.
🌌 The idea
Most “star map posters” online aren’t actually based on real sky data.
Many use approximations, fake constellations, or pre-rendered visuals.
I wanted something…
Building SkyMoment: A 4K Personalized Star Map Generator with Python, Skyfield and Real Astronomical Data
I recently shipped a small side project called SkyMoment — a generator that creates personalized 4K star map posters using real astronomical data.
You enter a date, time, and location.
SkyMoment recreates the exact night sky for that moment and renders it as a minimalist, print-ready 4000×4000 poster.
🔗 Live demo: https://skymoment.art/
This post is a breakdown of how the system works — from astronomical calculations to rendering and backend automation.
🌌 The idea
Most “star map posters” online aren’t actually based on real sky data.
Many 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 I wanted to turn this 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:
- date
- time
- location (lat/lon)
the pipeline does:
1. Convert local time to UTC
Skyfield requires accurate UTC timestamps.
2. Load planetary ephemeris
Using DE421 / DE422 depending on the build.
3. Load Hipparcos star catalog
This gives:
- RA/Dec
- magnitude
- proper motion
4. Transform everything into the user’s sky coordinates
Using Astropy AltAz transforms based on the observer’s position.
5. Filter stars
Only stars above a certain brightness threshold are rendered.
6. Split bright/faint stars
Bright stars use a stylized 8-point marker.
Faint stars use simple dots.
7. 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.
8. Render at 4000×4000 resolution
Matplotlib actually 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:
- preload 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:
1. User configures their moment
Chooses date/time/location and sees a preview.
2. User is redirected to Lemon Squeezy checkout
3. After payment, LS sends a webhook to Django
The webhook contains:
- the order ID
- the custom fields (title, location, datetime)
- the product variant
4. Django creates a generation job
Status: pending → generating → ready
5. A worker process runs the Python renderer
6. The final 4K poster is saved to disk
7. 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
Here is a reduced-size preview of a generated poster:
(Insert image URL here if you want)
The 4K version includes:
- precise star positions
- constellation lines
- minimal typography
- custom title & subtitle
- a clean dark theme
🚀 What’s next
On the roadmap:
- multiple poster templates
- faster rendering (possibly caching or partial reuse)
- more curated landing pages
- detailed generational 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!